バージョンと設定#
ソフトウェアバージョン:
langchain 0.3.25 pypi_0 pypi
langchain-community 0.3.25 pypi_0 pypi
langchain-core 0.3.65 pypi_0 pypi
langchain-ollama 0.3.3 pypi_0 pypi
langchain-openai 0.3.24 pypi_0 pypi
langchain-text-splitters 0.3.8 pypi_0 pypi
python
バージョン:3.10.16
要件#
エピソディックなタスクを実行する必要があります。各ステップで、まず従来の方法で解決策を求めます。その後、大規模言語モデルを使用して解決策を最適化し、最終的な結果を観察します。
実装#
ファイル構造
src/llm
├── agents.py
├── keys.toml
├── models.py
├── prompts
│ ├── __init__.py
│ ├── [xxxx] // あなたのシナリオ名
│ │ ├── human.txt
│ │ └── system.txt
│ └── utils.py
└── tools.py
まずローカルの Ollama で使用し、通った後により強力なモデルとの接続を考えます。例えば、私の方ではまず qwen2:7b
というモデルを使用しました。
# test/test_llm.py
from langchain.agents import create_structured_chat_agent
from src.llm.models import get_model
from src.llm.prompts.utils import load_prompts
def test_llm():
model = get_model("ollama", "qwen2:7b")
prompt = load_prompts(scenario="routing")
agent = create_structured_chat_agent(model, [], prompt)
result = agent.invoke({"input": "hello", "intermediate_steps": []})
print(result)
# models.py
from langchain_ollama import ChatOllama
from langchain_openai import ChatOpenAI
def get_model(provider: str, model: str, temperature: float = 0.3):
if provider == "ollama":
return ChatOllama(
model=model, temperature=temperature, base_url="http://localhost:11434"
) # 引数に注意、llmはmodel引数に渡す必要があります。さもなければValidation Errorが発生します。
elif provider == "openai":
return ChatOpenAI(...) # 省略
else:
raise ValueError("unsupported provider")
# prompts/utils.py
from pathlib import Path
from langchain.prompts import (
ChatPromptTemplate,
HumanMessagePromptTemplate,
SystemMessagePromptTemplate,
)
def load_prompts(scenario: str):
path = Path(__file__).parent / scenario
with open(path / "system.txt", "r", encoding="utf-8") as f:
s_template = f.read()
s_prompt = SystemMessagePromptTemplate.from_template(s_template)
with open(path / "human.txt", "r", encoding="utf-8") as f:
h_template = f.read()
h_prompt = HumanMessagePromptTemplate.from_template(h_template)
return ChatPromptTemplate.from_messages([s_prompt, h_prompt])
プロンプトファイル、参考リンク設定 https://smith.langchain.com/hub/hwchase17/structured-chat-agent
# human.txt
{input}
{agent_scratchpad}
(必ずJSONブロブで応答することを思い出してください)
# system.txt
人間にできるだけ役立ち、正確に応答してください。以下のツールにアクセスできます:
{tools}
アクションキー(ツール名)とアクション入力キー(ツール入力)を指定するためにJSONブロブを使用してください。
有効な「action」値: "Final Answer" または {tool_names}
$JSON_BLOBごとに1つのアクションのみを提供してください。次のように:
{{
"action": $TOOL_NAME,
"action_input": $INPUT
}}
この形式に従ってください:
質問:回答するための入力質問
考え:前のステップと次のステップを考慮する
アクション:
$JSON_BLOB
観察:アクション結果
... (考え/アクション/観察をN回繰り返す)
考え:何に応答するかを知っています
アクション:
{{
"action": "Final Answer",
"action_input": "人間への最終応答"
}}
始めましょう!常に単一のアクションの有効なJSONブロブで応答することを思い出してください。必要に応じてツールを使用してください。適切な場合は直接応答してください。形式はアクション:```$JSON_BLOB```その後観察
落とし穴#
1. バージョン#
langchain はまだ進化を続けており、以前のバージョンと現在のバージョンには一定のインターフェースの違いがありますので、特に注意が必要です。ネットで資料を調べる際には、タイムリーさが非常に重要です。
2. プロンプト#
create_structured_chat_agent
関数を使用してエージェントを作成する際には、プロンプト内に必ず tools
, tools_name
, agent_scratchpad
の 3 つのプレースホルダーが含まれていることに注意し、{}
で囲む必要があります。
さもなければ、エラー
ValueError: Prompt missing required variables: {'agent_scratchpad', 'tool_names', 'tools'}
が発生します。解析時に、このプロンプトテンプレートは
f-string
と見なされるため、{}
内の内容が自動的に変数値に置き換えられます。
更新 25/6/24#
従来の .txt
をプロンプトとして使用するのは拡張性が非常に低い(コメントをサポートしていないため)ため、jinja2
テンプレートを使用してプロンプトを管理することにしました。
これにより、コメントをサポートし、プレースホルダーを解析できます。
jinja
テンプレートは {{...}}
をプレースホルダーとして使用しますが、これは langchain
で使用される {...}
とは異なります。この 2 つは混用できないため、解析エラーが発生します。
system prompt
については、通常エージェントの初期化時に提供され、その後は変更されません。引数を渡す必要がある場合は、jinja
テンプレートを介して渡すことをお勧めします。
from langchain_core.prompts.string import jinja2_formatter
s_template = jinja2_formatter(
Path(path / "system.jinja").read_text(encoding="utf-8"),
... # プレースホルダーに対応する引数を渡す
)
s_prompt = SystemMessagePromptTemplate.from_template(s_template)
human prompt
、つまりエージェントの入力については、通常は各ステップでリアルタイムに更新されるため、jinja
を使用して読み込むことも、.invoke()
メソッドを介して渡すこともできます。ただし、前者ではプレースホルダーを {{...}}
形式で記述し、system prompt
と同様の方法で human prompt
をインポートする必要があります。後者では、langchain
スタイルの {...}
をプレースホルダーとして使用し、文字列の形式で直接インポートする必要があります(以下のように)。
h_template = Path(path / "human.jinja").read_text(encoding="utf-8")
h_prompt = HumanMessagePromptTemplate.from_template(h_template)
3. 呼び出し#
agent.invoke()
を実行する際には、input
フィールドの内容を提供するだけでなく、intermediate_steps
フィールドの値も提供する必要があります。
さもなければ、エラー
KeyError: 'intermediate_steps'
が発生します。
更新#
AgentExecutor を使用してエージェントをラップすることで、より詳細なカスタマイズが可能になり、デバッグ情報を返すことができます。
## 元のコード
agent = create_structured_chat_agent(model, [], prompt)
result = agent.invoke({"input": "hello", "intermediate_steps": []})
## 更新されたコード
agent = create_structured_chat_agent(model, [], prompt)
executor = AgentExecutor.from_agent_and_tools(
agent=agent, tools=[], verbose=True, return_intermediate_steps=True
)
result = executor.invoke({"input": "hello"})
より詳細なカスタマイズが可能になる一方で、intermediate_steps
パラメータを手動で渡す必要がなくなります。