langchain-fundamentals について
langchain-fundamentalsは、PythonまたはTypeScriptでLangChainエージェントを開発するためのスキルです。`create_agent()`、ツール、ミドルウェア、状態の永続化、構造化出力を扱います。
主な機能
- 01`create_agent()`によるエージェント構築
- 02デコレーターや関数でのツール定義
- 03ミドルウェアによるフロー制御
- 04checkpointerによる状態保存
- 05構造化出力とモデルの設定
活用シーン
- 01ツールを呼び出すエージェントの構築
- 02ツール実行に人間の承認を追加
- 03呼び出し間で会話状態を保持
- 04エージェントのループ制限と結果取得
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ langchain-ai/ skills-benchmarks --skill langchain-fundamentalsインストール後、Claude Code で/langchain-fundamentalsを入力して読み込まれたか確認します。
詳細
<create_agent>
create_agent を使ったエージェントの作成
エージェントを構築する際は、create_agent() の使用が推奨されます。エージェントループ、ツールの実行、状態管理を処理します。
エージェント設定オプション
| パラメーター | 目的 | 例 |
|---|---|---|
model | 使用する LLM | "anthropic:claude-sonnet-4-5" またはモデルインスタンス |
tools | ツールのリスト | [search, calculator] |
system_prompt / systemPrompt | エージェントへの指示 | "You are a helpful assistant" |
checkpointer | 状態の永続化 | MemorySaver() |
middleware | 処理フック | [HumanInTheLoopMiddleware](Python)/[humanInTheLoopMiddleware({...})](TypeScript) |
| </create_agent> |
@tool def get_weather(location: str) -> str: """Get current weather for a location.
Args:
location: City name
"""
return f"Weather in {location}: Sunny, 72F"
agent = create_agent( model="anthropic:claude-sonnet-4-5", tools=[get_weather], system_prompt="You are a helpful assistant." )
result = agent.invoke({ "messages": [{"role": "user", "content": "What's the weather in Paris?"}] }) print(result["messages"][-1].content)
</python>
<typescript>
```typescript
import { createAgent } from "langchain";
import { tool } from "@langchain/core/tools";
import { z } from "zod";
const getWeather = tool(
async ({ location }) => `Weather in ${location}: Sunny, 72F`,
{
name: "get_weather",
description: "Get current weather for a location.",
schema: z.object({ location: z.string().describe("City name") }),
}
);
const agent = createAgent({
model: "anthropic:claude-sonnet-4-5",
tools: [getWeather],
systemPrompt: "You are a helpful assistant.",
});
const result = await agent.invoke({
messages: [{ role: "user", content: "What's the weather in Paris?" }],
});
console.log(result.messages[result.messages.length - 1].content);
呼び出し間で会話状態を維持するには、MemorySaver チェックポインターを追加します。
```python
from langchain.agents import create_agent
from langgraph.checkpoint.memory import MemorySaver
checkpointer = MemorySaver()
agent = create_agent( model="anthropic:claude-sonnet-4-5", tools=[search], checkpointer=checkpointer, )
config = {"configurable": {"thread_id": "user-123"}} agent.invoke({"messages": [{"role": "user", "content": "My name is Alice"}]}, config=config) result = agent.invoke({"messages": [{"role": "user", "content": "What's my name?"}]}, config=config)
Agent remembers: "Your name is Alice"
</python>
<typescript>
呼び出し間で会話状態を維持するには、MemorySaver チェックポインターを追加します。
```typescript
import { createAgent } from "langchain";
import { MemorySaver } from "@langchain/langgraph";
const checkpointer = new MemorySaver();
const agent = createAgent({
model: "anthropic:claude-sonnet-4-5",
tools: [search],
checkpointer,
});
const config = { configurable: { thread_id: "user-123" } };
await agent.invoke({ messages: [{ role: "user", content: "My name is Alice" }] }, config);
const result = await agent.invoke({ messages: [{ role: "user", content: "What's my name?" }] }, config);
// Agent remembers: "Your name is Alice"
## ツールの定義
ツールは、エージェントが呼び出せる関数です。@tool デコレーター(Python)または tool() 関数(TypeScript)を使用します。
@tool def calculate(expression: str) -> str: """Evaluate a mathematical expression.
Args:
expression: Math expression like "2 + 2" or "10 * 5"
"""
return str(eval(expression))
</python>
<typescript>
```typescript
import { tool } from "@langchain/core/tools";
import { z } from "zod";
const calculate = tool(
async ({ expression }) => String(eval(expression)),
{
name: "calculate",
description: "Evaluate a mathematical expression.",
schema: z.object({
expression: z.string().describe("Math expression like '2 + 2' or '10 * 5'"),
}),
}
);
## エージェント制御のためのミドルウェア
ミドルウェアはエージェントループに介入し、人間による承認、エラー処理、ログ記録などを追加します。本番環境向けのエージェントにはミドルウェアへの深い理解が不可欠です。承認ワークフローには HumanInTheLoopMiddleware(Python)/humanInTheLoopMiddleware(TypeScript)を、カスタムフックには @wrap_tool_call(Python)/createMiddleware(TypeScript)を使用します。
主なインポート:
from langchain.agents.middleware import HumanInTheLoopMiddleware, wrap_tool_call
import { humanInTheLoopMiddleware, createMiddleware } from "langchain";
主なパターン:
- HITL:
middleware=[HumanInTheLoopMiddleware(interrupt_on={"dangerous_tool": True})]—checkpointerとthread_idが必要です - 割り込み後の再開:
agent.invoke(Command(resume={"decisions": [{"type": "approve"}]}), config=config) - カスタムミドルウェア:
@wrap_tool_callデコレーター(Python)またはcreateMiddleware({ wrapToolCall: ... })(TypeScript)
<structured_output>
構造化出力
response_format または with_structured_output() を使うと、型付けされ、検証済みの応答をエージェントから取得できます。
class ContactInfo(BaseModel): name: str email: str phone: str = Field(description="Phone number with area code")
Option 1: Agent with structured output
agent = create_agent(model="gpt-4.1", tools=[search], response_format=ContactInfo) result = agent.invoke({"messages": [{"role": "user", "content": "Find contact for John"}]}) print(result["structured_response"]) # ContactInfo(name='John', ...)
Option 2: Model-level structured output (no agent needed)
from langchain_openai import ChatOpenAI model = ChatOpenAI(model="gpt-4.1") structured_model = model.with_structured_output(ContactInfo) response = structured_model.invoke("Extract: John, [email protected], 555-1234")
ContactInfo(name='John', email='[email protected]', phone='555-1234')
</python>
<typescript>
```typescript
import { ChatOpenAI } from "@langchain/openai";
import { z } from "zod";
const ContactInfo = z.object({
name: z.string(),
email: z.string().email(),
phone: z.string().describe("Phone number with area code"),
});
// Model-level structured output
const model = new ChatOpenAI({ model: "gpt-4.1" });
const structuredModel = model.withStructuredOutput(ContactInfo);
const response = await structuredModel.invoke("Extract: John, [email protected], 555-1234");
// { name: 'John', email: '[email protected]', phone: '555-1234' }
<model_config>
モデルの設定
create_agent は、モデル文字列("anthropic:claude-sonnet-4-5"、"openai:gpt-4.1")またはカスタム設定用のモデルインスタンスを受け取ります。
from langchain_anthropic import ChatAnthropic
agent = create_agent(model=ChatAnthropic(model="claude-sonnet-4-5", temperature=0), tools=[...])
</model_config>
明確な説明を記述すると、各ツールをいつ使うべきかエージェントが判断しやすくなります。 ```python # WRONG: Vague or missing description @tool def bad_tool(input: str) -> str: """Does stuff.""" return "result"CORRECT: Clear, specific description with Args
@tool def search(query: str) -> str: """Search the web for current information about a topic.
Use this when you need recent data or facts.
Args:
query: The search query (2-10 words recommended)
"""
return web_search(query)
</python>
<typescript>
明確な説明を記述すると、各ツールをいつ使うべきかエージェントが判断しやすくなります。
```typescript
// WRONG: Vague description
const badTool = tool(async ({ input }) => "result", {
name: "bad_tool",
description: "Does stuff.", // Too vague!
schema: z.object({ input: z.string() }),
});
// CORRECT: Clear, specific description
const search = tool(async ({ query }) => webSearch(query), {
name: "search",
description: "Search the web for current information about a topic. Use this when you need recent data or facts.",
schema: z.object({
query: z.string().describe("The search query (2-10 words recommended)"),
}),
});
呼び出し間で会話の記憶を保持するには、チェックポインターと thread_id を追加します。
```python
# WRONG: No persistence - agent forgets between calls
agent = create_agent(model="anthropic:claude-sonnet-4-5", tools=[search])
agent.invoke({"messages": [{"role": "user", "content": "I'm Bob"}]})
agent.invoke({"messages": [{"role": "user", "content": "What's my name?"}]})
# Agent doesn't remember!
CORRECT: Add checkpointer and thread_id
from langgraph.checkpoint.memory import MemorySaver
agent = create_agent( model="anthropic:claude-sonnet-4-5", tools=[search], checkpointer=MemorySaver(), ) config = {"configurable": {"thread_id": "session-1"}} agent.invoke({"messages": [{"role": "user", "content": "I'm Bob"}]}, config=config) agent.invoke({"messages": [{"role": "user", "content": "What's my name?"}]}, config=config)
Agent remembers: "Your name is Bob"
</python>
<typescript>
呼び出し間で会話の記憶を保持するには、チェックポインターと thread_id を追加します。
```typescript
// WRONG: No persistence
const agent = createAgent({ model: "anthropic:claude-sonnet-4-5", tools: [search] });
await agent.invoke({ messages: [{ role: "user", content: "I'm Bob" }] });
await agent.invoke({ messages: [{ role: "user", content: "What's my name?" }] });
// Agent doesn't remember!
// CORRECT: Add checkpointer and thread_id
import { MemorySaver } from "@langchain/langgraph";
const agent = createAgent({
model: "anthropic:claude-sonnet-4-5",
tools: [search],
checkpointer: new MemorySaver(),
});
const config = { configurable: { thread_id: "session-1" } };
await agent.invoke({ messages: [{ role: "user", content: "I'm Bob" }] }, config);
await agent.invoke({ messages: [{ role: "user", content: "What's my name?" }] }, config);
// Agent remembers: "Your name is Bob"
エージェントのループが止まらなくなるのを防ぐには、invoke の設定で recursion_limit を指定します。
```python
# WRONG: No iteration limit - could loop forever
result = agent.invoke({"messages": [("user", "Do research")]})
CORRECT: Set recursion_limit in config
result = agent.invoke( {"messages": [("user", "Do research")]}, config={"recursion_limit": 10}, # Stop after 10 steps )
</python>
<typescript>
エージェントのループが止まらなくなるのを防ぐには、invoke の設定で recursionLimit を指定します。
```typescript
// WRONG: No iteration limit
const result = await agent.invoke({ messages: [["user", "Do research"]] });
// CORRECT: Set recursionLimit in config
const result = await agent.invoke(
{ messages: [["user", "Do research"]] },
{ recursionLimit: 10 }, // Stop after 10 steps
);
result.content を直接参照するのではなく、result の messages 配列を参照します。
```python
# WRONG: Trying to access result.content directly
result = agent.invoke({"messages": [{"role": "user", "content": "Hello"}]})
print(result.content) # AttributeError!
CORRECT: Access messages from result dict
result = agent.invoke({"messages": [{"role": "user", "content": "Hello"}]}) print(result["messages"][-1].content) # Last message content
</python>
<typescript>
result.content を直接参照するのではなく、result の messages 配列を参照します。
```typescript
// WRONG: Trying to access result.content directly
const result = await agent.invoke({ messages: [{ role: "user", content: "Hello" }] });
console.log(result.content); // undefined!
// CORRECT: Access messages from result object
const result = await agent.invoke({ messages: [{ role: "user", content: "Hello" }] });
console.log(result.messages[result.messages.length - 1].content); // Last message content