ni.agentkit 0.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agentkit/__init__.py +57 -0
- agentkit/_cli.py +72 -0
- agentkit/agents/__init__.py +0 -0
- agentkit/agents/agent.py +364 -0
- agentkit/agents/base_agent.py +59 -0
- agentkit/agents/orchestrators.py +62 -0
- agentkit/docs/Architecture.md +536 -0
- agentkit/docs/QuickStart.md +806 -0
- agentkit/docs/README.md +119 -0
- agentkit/docs/Reference.md +576 -0
- agentkit/docs/TestReport.md +80 -0
- agentkit/examples/__init__.py +0 -0
- agentkit/examples/ollama/01_basic_chat.py +34 -0
- agentkit/examples/ollama/02_tool_calling.py +70 -0
- agentkit/examples/ollama/03_skill_usage.py +86 -0
- agentkit/examples/ollama/04_multi_agent.py +84 -0
- agentkit/examples/ollama/05_guardrail.py +101 -0
- agentkit/examples/ollama/06_orchestration.py +123 -0
- agentkit/examples/ollama/07_sync_async_stream.py +180 -0
- agentkit/examples/ollama/08_memory.py +201 -0
- agentkit/examples/ollama/README.md +51 -0
- agentkit/examples/ollama/__init__.py +0 -0
- agentkit/examples/quickstart.py +204 -0
- agentkit/examples/standard/01_basic_chat.py +33 -0
- agentkit/examples/standard/02_tool_calling.py +70 -0
- agentkit/examples/standard/03_skill_usage.py +89 -0
- agentkit/examples/standard/04_multi_agent.py +87 -0
- agentkit/examples/standard/05_guardrail.py +104 -0
- agentkit/examples/standard/06_orchestration.py +122 -0
- agentkit/examples/standard/07_sync_async_stream.py +171 -0
- agentkit/examples/standard/08_memory.py +140 -0
- agentkit/examples/standard/README.md +31 -0
- agentkit/examples/standard/__init__.py +0 -0
- agentkit/examples/test_ollama.py +272 -0
- agentkit/llm/__init__.py +0 -0
- agentkit/llm/adapters/__init__.py +0 -0
- agentkit/llm/adapters/anthropic_adapter.py +192 -0
- agentkit/llm/adapters/google_adapter.py +184 -0
- agentkit/llm/adapters/ollama_adapter.py +250 -0
- agentkit/llm/adapters/openai_adapter.py +183 -0
- agentkit/llm/adapters/openai_compatible.py +35 -0
- agentkit/llm/base.py +66 -0
- agentkit/llm/cache.py +121 -0
- agentkit/llm/middleware.py +133 -0
- agentkit/llm/registry.py +138 -0
- agentkit/llm/types.py +191 -0
- agentkit/memory/__init__.py +0 -0
- agentkit/memory/base.py +47 -0
- agentkit/memory/mem0_provider.py +48 -0
- agentkit/runner/__init__.py +0 -0
- agentkit/runner/context.py +47 -0
- agentkit/runner/events.py +36 -0
- agentkit/runner/runner.py +105 -0
- agentkit/safety/__init__.py +0 -0
- agentkit/safety/guardrails.py +55 -0
- agentkit/safety/permissions.py +41 -0
- agentkit/skills/__init__.py +0 -0
- agentkit/skills/loader.py +90 -0
- agentkit/skills/models.py +106 -0
- agentkit/skills/registry.py +48 -0
- agentkit/tools/__init__.py +0 -0
- agentkit/tools/base_tool.py +44 -0
- agentkit/tools/function_tool.py +118 -0
- agentkit/tools/skill_toolset.py +199 -0
- agentkit/utils/__init__.py +0 -0
- agentkit/utils/schema.py +83 -0
- ni_agentkit-0.3.1.dist-info/METADATA +157 -0
- ni_agentkit-0.3.1.dist-info/RECORD +72 -0
- ni_agentkit-0.3.1.dist-info/WHEEL +5 -0
- ni_agentkit-0.3.1.dist-info/entry_points.txt +2 -0
- ni_agentkit-0.3.1.dist-info/licenses/LICENSE +21 -0
- ni_agentkit-0.3.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""
|
|
2
|
+
示例 2:带工具的 Agent — Function Calling
|
|
3
|
+
|
|
4
|
+
演示 @function_tool 装饰器:一行代码把 Python 函数变成 LLM 可调用的工具。
|
|
5
|
+
|
|
6
|
+
运行前请设置环境变量:
|
|
7
|
+
export OPENAI_API_KEY="sk-..."
|
|
8
|
+
|
|
9
|
+
运行:
|
|
10
|
+
python examples/standard/02_tool_calling.py
|
|
11
|
+
"""
|
|
12
|
+
import sys, os
|
|
13
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", ".."))
|
|
14
|
+
|
|
15
|
+
from agentkit import Agent, Runner, function_tool
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# ===== 定义工具 =====
|
|
19
|
+
|
|
20
|
+
@function_tool
|
|
21
|
+
def add(a: int, b: int) -> str:
|
|
22
|
+
"""两个数字相加"""
|
|
23
|
+
return str(a + b)
|
|
24
|
+
|
|
25
|
+
@function_tool
|
|
26
|
+
def multiply(a: int, b: int) -> str:
|
|
27
|
+
"""两个数字相乘"""
|
|
28
|
+
return str(a * b)
|
|
29
|
+
|
|
30
|
+
@function_tool
|
|
31
|
+
def get_weather(city: str) -> str:
|
|
32
|
+
"""获取指定城市的天气信息"""
|
|
33
|
+
weather_data = {
|
|
34
|
+
"北京": "晴,25°C",
|
|
35
|
+
"上海": "多云,22°C",
|
|
36
|
+
"深圳": "阵雨,28°C",
|
|
37
|
+
}
|
|
38
|
+
return weather_data.get(city, f"{city}:暂无数据")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# ===== 创建 Agent =====
|
|
42
|
+
|
|
43
|
+
agent = Agent(
|
|
44
|
+
name="smart-assistant",
|
|
45
|
+
instructions="你是一个全能助手。可以做数学计算和查天气。根据用户需求选择合适的工具。回答简洁。",
|
|
46
|
+
model="gpt-4o",
|
|
47
|
+
tools=[add, multiply, get_weather],
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# ===== 运行测试 =====
|
|
52
|
+
|
|
53
|
+
queries = [
|
|
54
|
+
"请计算 15 + 27 的结果",
|
|
55
|
+
"3 乘以 7 等于多少?",
|
|
56
|
+
"北京今天天气如何?",
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
for q in queries:
|
|
60
|
+
print(f"\n用户: {q}")
|
|
61
|
+
result = Runner.run_sync(agent, input=q)
|
|
62
|
+
if result.success:
|
|
63
|
+
print(f"助手: {result.final_output}")
|
|
64
|
+
else:
|
|
65
|
+
print(f"❌ 错误: {result.error}")
|
|
66
|
+
|
|
67
|
+
# 展示工具调用
|
|
68
|
+
for event in result.events:
|
|
69
|
+
if event.type == "tool_result":
|
|
70
|
+
print(f" 🔧 工具调用: {event.data}")
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""
|
|
2
|
+
示例 3:带 Skill 的 Agent — 领域知识包
|
|
3
|
+
|
|
4
|
+
演示 Skill 的核心用法:
|
|
5
|
+
- 代码中定义 Skill(Frontmatter + Instructions)
|
|
6
|
+
- Skill 三级渐进式加载(L1 → L2 → L3)
|
|
7
|
+
- Skill 与 Tool 的协作
|
|
8
|
+
|
|
9
|
+
运行前请设置环境变量:
|
|
10
|
+
export OPENAI_API_KEY="sk-..."
|
|
11
|
+
|
|
12
|
+
运行:
|
|
13
|
+
python examples/standard/03_skill_usage.py
|
|
14
|
+
"""
|
|
15
|
+
import sys, os
|
|
16
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", ".."))
|
|
17
|
+
|
|
18
|
+
from agentkit import Agent, Runner, Skill, SkillFrontmatter, SkillResources, function_tool
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# ===== 定义工具 =====
|
|
22
|
+
|
|
23
|
+
@function_tool
|
|
24
|
+
def get_weather(city: str) -> str:
|
|
25
|
+
"""获取指定城市的天气信息"""
|
|
26
|
+
weather_data = {
|
|
27
|
+
"北京": "晴,25°C",
|
|
28
|
+
"上海": "多云,22°C",
|
|
29
|
+
"深圳": "阵雨,28°C",
|
|
30
|
+
"广州": "晴,30°C",
|
|
31
|
+
"成都": "阴,18°C",
|
|
32
|
+
}
|
|
33
|
+
return weather_data.get(city, f"{city}:暂无数据")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# ===== 定义 Skill =====
|
|
37
|
+
|
|
38
|
+
weather_skill = Skill(
|
|
39
|
+
frontmatter=SkillFrontmatter(
|
|
40
|
+
name="weather-analysis",
|
|
41
|
+
description="天气分析技能,查询天气并给出穿衣建议",
|
|
42
|
+
),
|
|
43
|
+
instructions="""## 天气分析步骤
|
|
44
|
+
|
|
45
|
+
1. 使用 get_weather 工具查询用户指定城市的天气
|
|
46
|
+
2. 根据天气情况给出穿衣建议:
|
|
47
|
+
- 温度 > 30°C:建议穿短袖、注意防晒
|
|
48
|
+
- 温度 20-30°C:建议穿薄外套
|
|
49
|
+
- 温度 < 20°C:建议穿厚外套
|
|
50
|
+
3. 如果有雨,额外提醒带伞
|
|
51
|
+
4. 用简洁的中文回复用户""",
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# ===== 创建带 Skill 的 Agent =====
|
|
56
|
+
|
|
57
|
+
agent = Agent(
|
|
58
|
+
name="skill-agent",
|
|
59
|
+
instructions="你是一个智能助手,可以使用专业技能来完成任务。",
|
|
60
|
+
model="gpt-4o",
|
|
61
|
+
skills=[weather_skill], # ⭐ Skill 作为一等公民
|
|
62
|
+
tools=[get_weather],
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# ===== 运行测试 =====
|
|
67
|
+
|
|
68
|
+
queries = [
|
|
69
|
+
"深圳今天适合穿什么衣服?",
|
|
70
|
+
"成都现在冷不冷?需要穿什么?",
|
|
71
|
+
"广州今天出门要注意什么?",
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
for q in queries:
|
|
75
|
+
print(f"\n用户: {q}")
|
|
76
|
+
result = Runner.run_sync(agent, input=q)
|
|
77
|
+
if result.success:
|
|
78
|
+
print(f"助手: {result.final_output}")
|
|
79
|
+
else:
|
|
80
|
+
print(f"❌ 错误: {result.error}")
|
|
81
|
+
|
|
82
|
+
# 展示 Skill 和工具调用
|
|
83
|
+
for event in result.events:
|
|
84
|
+
if event.type == "tool_result":
|
|
85
|
+
tool_name = event.data.get("tool", "")
|
|
86
|
+
if tool_name == "load_skill":
|
|
87
|
+
print(f" 📚 加载了 Skill: {event.data.get('result', {}).get('skill_name', '')}")
|
|
88
|
+
else:
|
|
89
|
+
print(f" 🔧 工具调用: {event.data}")
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""
|
|
2
|
+
示例 4:多 Agent 协作 — Handoff 与 as_tool
|
|
3
|
+
|
|
4
|
+
演示两种 Agent 协作模式:
|
|
5
|
+
- as_tool(委派):Agent A 把 Agent B 当工具调用,完成后控制权返回 A
|
|
6
|
+
- Handoff(转介):Agent A 把整个对话交给 Agent B,控制权完全转移
|
|
7
|
+
|
|
8
|
+
运行前请设置环境变量:
|
|
9
|
+
export OPENAI_API_KEY="sk-..."
|
|
10
|
+
|
|
11
|
+
运行:
|
|
12
|
+
python examples/standard/04_multi_agent.py
|
|
13
|
+
"""
|
|
14
|
+
import sys, os
|
|
15
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", ".."))
|
|
16
|
+
|
|
17
|
+
from agentkit import Agent, Runner
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# ============================================================
|
|
21
|
+
# 模式 A:as_tool(委派)
|
|
22
|
+
# ============================================================
|
|
23
|
+
|
|
24
|
+
print("=" * 50)
|
|
25
|
+
print(" 模式 A:as_tool(委派)")
|
|
26
|
+
print("=" * 50)
|
|
27
|
+
|
|
28
|
+
# 专家 Agent
|
|
29
|
+
researcher = Agent(
|
|
30
|
+
name="researcher",
|
|
31
|
+
instructions="你是一个研究助手。收到问题后,给出简短的研究结论(不超过 3 句话)。",
|
|
32
|
+
model="gpt-4o",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
# 主管 Agent,把研究员当工具用
|
|
36
|
+
manager = Agent(
|
|
37
|
+
name="manager",
|
|
38
|
+
instructions="你是项目经理。需要研究信息时调用 research 工具。综合研究结果给出你的建议。",
|
|
39
|
+
model="gpt-4o",
|
|
40
|
+
tools=[
|
|
41
|
+
researcher.as_tool("research", "调用研究助手获取研究信息"),
|
|
42
|
+
],
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
result = Runner.run_sync(manager, input="帮我调研 Python 异步编程的最佳实践")
|
|
46
|
+
if result.success:
|
|
47
|
+
print(f"\n✅ 回复: {result.final_output}")
|
|
48
|
+
else:
|
|
49
|
+
print(f"\n❌ 错误: {result.error}")
|
|
50
|
+
|
|
51
|
+
for event in result.events:
|
|
52
|
+
if event.type == "tool_result":
|
|
53
|
+
print(f" 🔧 研究员返回: {str(event.data)[:100]}")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# ============================================================
|
|
57
|
+
# 模式 B:Handoff(转介)
|
|
58
|
+
# ============================================================
|
|
59
|
+
|
|
60
|
+
print(f"\n{'=' * 50}")
|
|
61
|
+
print(" 模式 B:Handoff(转介)")
|
|
62
|
+
print("=" * 50)
|
|
63
|
+
|
|
64
|
+
billing_agent = Agent(
|
|
65
|
+
name="billing",
|
|
66
|
+
instructions="你是账单专家。处理所有账单相关的问题,给出专业的解答。",
|
|
67
|
+
model="gpt-4o",
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
tech_agent = Agent(
|
|
71
|
+
name="tech",
|
|
72
|
+
instructions="你是技术支持专家。处理所有技术相关的问题。",
|
|
73
|
+
model="gpt-4o",
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
triage_agent = Agent(
|
|
77
|
+
name="triage",
|
|
78
|
+
instructions="你是客服分诊员。根据用户问题类型,转交给合适的专家:账单问题转给 billing,技术问题转给 tech。",
|
|
79
|
+
model="gpt-4o",
|
|
80
|
+
handoffs=[billing_agent, tech_agent],
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
result = Runner.run_sync(triage_agent, input="我的账单金额好像不对,比上个月多了很多")
|
|
84
|
+
if result.success:
|
|
85
|
+
print(f"\n✅ 最终由 [{result.last_agent}] 处理: {result.final_output}")
|
|
86
|
+
else:
|
|
87
|
+
print(f"\n❌ 错误: {result.error}")
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""
|
|
2
|
+
示例 5:安全护栏 — Guardrail 与权限控制
|
|
3
|
+
|
|
4
|
+
演示三层安全机制:
|
|
5
|
+
- 输入护栏(InputGuardrail):拦截不安全的用户输入
|
|
6
|
+
- 输出护栏(OutputGuardrail):检查 Agent 的输出内容
|
|
7
|
+
- 权限控制(PermissionPolicy):限制可调用的工具
|
|
8
|
+
|
|
9
|
+
运行前请设置环境变量:
|
|
10
|
+
export OPENAI_API_KEY="sk-..."
|
|
11
|
+
|
|
12
|
+
运行:
|
|
13
|
+
python examples/standard/05_guardrail.py
|
|
14
|
+
"""
|
|
15
|
+
import sys, os
|
|
16
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", ".."))
|
|
17
|
+
|
|
18
|
+
from agentkit import (
|
|
19
|
+
Agent, Runner, function_tool,
|
|
20
|
+
input_guardrail, output_guardrail, GuardrailResult,
|
|
21
|
+
PermissionPolicy,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# ===== 定义工具 =====
|
|
26
|
+
|
|
27
|
+
@function_tool
|
|
28
|
+
def read_file(filename: str) -> str:
|
|
29
|
+
"""读取文件内容"""
|
|
30
|
+
return f"[模拟] 文件 {filename} 的内容:Hello World"
|
|
31
|
+
|
|
32
|
+
@function_tool
|
|
33
|
+
def delete_file(filename: str) -> str:
|
|
34
|
+
"""删除文件"""
|
|
35
|
+
return f"[模拟] 已删除文件 {filename}"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# ===== 定义护栏 =====
|
|
39
|
+
|
|
40
|
+
@input_guardrail
|
|
41
|
+
async def block_sensitive_words(ctx):
|
|
42
|
+
"""检查输入是否包含敏感词"""
|
|
43
|
+
sensitive = ["密码", "身份证", "银行卡号", "社保号"]
|
|
44
|
+
for word in sensitive:
|
|
45
|
+
if word in ctx.input:
|
|
46
|
+
return GuardrailResult(triggered=True, reason=f"包含敏感词: {word}")
|
|
47
|
+
return GuardrailResult(triggered=False)
|
|
48
|
+
|
|
49
|
+
@output_guardrail
|
|
50
|
+
async def check_output_safety(ctx, output):
|
|
51
|
+
"""检查输出是否安全"""
|
|
52
|
+
dangerous_words = ["删除成功", "已格式化"]
|
|
53
|
+
output_str = str(output)
|
|
54
|
+
for word in dangerous_words:
|
|
55
|
+
if word in output_str:
|
|
56
|
+
return GuardrailResult(triggered=True, reason=f"输出包含危险内容: {word}")
|
|
57
|
+
return GuardrailResult(triggered=False)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# ===== 创建带安全护栏的 Agent =====
|
|
61
|
+
|
|
62
|
+
agent = Agent(
|
|
63
|
+
name="safe-agent",
|
|
64
|
+
instructions="你是一个安全的助手。可以帮用户读取文件,但不能删除文件。",
|
|
65
|
+
model="gpt-4o",
|
|
66
|
+
tools=[read_file, delete_file],
|
|
67
|
+
input_guardrails=[block_sensitive_words],
|
|
68
|
+
output_guardrails=[check_output_safety],
|
|
69
|
+
permission_policy=PermissionPolicy(
|
|
70
|
+
mode="ask",
|
|
71
|
+
allowed_tools={"read_file"}, # 只允许读取,不允许删除
|
|
72
|
+
),
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# ===== 运行测试 =====
|
|
77
|
+
|
|
78
|
+
print("=" * 50)
|
|
79
|
+
print(" 测试输入护栏")
|
|
80
|
+
print("=" * 50)
|
|
81
|
+
|
|
82
|
+
# 测试 1:敏感请求 → 被拦截
|
|
83
|
+
result = Runner.run_sync(agent, input="请告诉我管理员的密码")
|
|
84
|
+
print(f"\n请求: '请告诉我管理员的密码'")
|
|
85
|
+
print(f"结果: {'🛡️ 已拦截 — ' + result.error if result.error else result.final_output}")
|
|
86
|
+
|
|
87
|
+
# 测试 2:正常请求 → 通过
|
|
88
|
+
result = Runner.run_sync(agent, input="请读取 config.txt 文件")
|
|
89
|
+
print(f"\n请求: '请读取 config.txt 文件'")
|
|
90
|
+
print(f"结果: {result.final_output if result.success else '❌ ' + str(result.error)}")
|
|
91
|
+
|
|
92
|
+
print(f"\n{'=' * 50}")
|
|
93
|
+
print(" 测试权限控制")
|
|
94
|
+
print("=" * 50)
|
|
95
|
+
|
|
96
|
+
# 测试 3:尝试调用未授权的工具 → 被拒绝
|
|
97
|
+
result = Runner.run_sync(agent, input="请删除 temp.txt 文件")
|
|
98
|
+
print(f"\n请求: '请删除 temp.txt 文件'")
|
|
99
|
+
print(f"结果: {result.final_output if result.success else '🔒 ' + str(result.error)}")
|
|
100
|
+
|
|
101
|
+
# 查看权限拒绝事件
|
|
102
|
+
for event in result.events:
|
|
103
|
+
if event.type == "permission_denied":
|
|
104
|
+
print(f" 🔒 权限拒绝: {event.data}")
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""
|
|
2
|
+
示例 6:编排 Agent — 顺序执行、并行执行、循环执行
|
|
3
|
+
|
|
4
|
+
演示三种编排模式:
|
|
5
|
+
- SequentialAgent:按顺序执行子 Agent(流水线)
|
|
6
|
+
- ParallelAgent:并行执行子 Agent(分支隔离)
|
|
7
|
+
- LoopAgent:循环执行直到 escalate 或达到上限
|
|
8
|
+
|
|
9
|
+
运行前请设置环境变量:
|
|
10
|
+
export OPENAI_API_KEY="sk-..."
|
|
11
|
+
|
|
12
|
+
运行:
|
|
13
|
+
python examples/standard/06_orchestration.py
|
|
14
|
+
"""
|
|
15
|
+
import sys, os
|
|
16
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", ".."))
|
|
17
|
+
|
|
18
|
+
from agentkit import Agent, Runner, SequentialAgent, ParallelAgent, LoopAgent
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# ============================================================
|
|
22
|
+
# 模式 A:顺序执行 — 报告生成流水线
|
|
23
|
+
# ============================================================
|
|
24
|
+
|
|
25
|
+
print("=" * 50)
|
|
26
|
+
print(" SequentialAgent — 报告生成流水线")
|
|
27
|
+
print("=" * 50)
|
|
28
|
+
|
|
29
|
+
pipeline = SequentialAgent(
|
|
30
|
+
name="report-pipeline",
|
|
31
|
+
sub_agents=[
|
|
32
|
+
Agent(
|
|
33
|
+
name="extractor",
|
|
34
|
+
instructions="你是数据提取专家。从用户输入中提取所有关键数据点,以列表形式输出。",
|
|
35
|
+
model="gpt-4o",
|
|
36
|
+
),
|
|
37
|
+
Agent(
|
|
38
|
+
name="analyzer",
|
|
39
|
+
instructions="你是数据分析专家。分析上文提取的数据点,找出趋势和规律,给出 2-3 条洞察。",
|
|
40
|
+
model="gpt-4o",
|
|
41
|
+
),
|
|
42
|
+
Agent(
|
|
43
|
+
name="reporter",
|
|
44
|
+
instructions="你是报告撰写专家。将上文的分析结果写成一段简洁的中文报告(不超过 100 字)。",
|
|
45
|
+
model="gpt-4o",
|
|
46
|
+
),
|
|
47
|
+
],
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
result = Runner.run_sync(pipeline, input="今年Q1销售额1000万,Q2增长到1500万,Q3下降到1200万,Q4预计1800万")
|
|
51
|
+
print(f"\n输入: 今年Q1销售额1000万...")
|
|
52
|
+
for event in result.events:
|
|
53
|
+
if event.type == "final_output":
|
|
54
|
+
print(f" [{event.agent}] {event.data}")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# ============================================================
|
|
58
|
+
# 模式 B:并行执行 — 多维度分析
|
|
59
|
+
# ============================================================
|
|
60
|
+
|
|
61
|
+
print(f"\n{'=' * 50}")
|
|
62
|
+
print(" ParallelAgent — 多维度并行分析")
|
|
63
|
+
print("=" * 50)
|
|
64
|
+
|
|
65
|
+
parallel = ParallelAgent(
|
|
66
|
+
name="multi-analysis",
|
|
67
|
+
sub_agents=[
|
|
68
|
+
Agent(
|
|
69
|
+
name="financial",
|
|
70
|
+
instructions="你是财务分析师。用一句话分析给定数据的财务状况。",
|
|
71
|
+
model="gpt-4o",
|
|
72
|
+
),
|
|
73
|
+
Agent(
|
|
74
|
+
name="market",
|
|
75
|
+
instructions="你是市场分析师。用一句话分析给定数据反映的市场趋势。",
|
|
76
|
+
model="gpt-4o",
|
|
77
|
+
),
|
|
78
|
+
Agent(
|
|
79
|
+
name="risk",
|
|
80
|
+
instructions="你是风险分析师。用一句话分析给定数据中的潜在风险。",
|
|
81
|
+
model="gpt-4o",
|
|
82
|
+
),
|
|
83
|
+
],
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
result = Runner.run_sync(parallel, input="公司年收入 5 亿,同比增长 20%,但负债率从 30% 升至 45%")
|
|
87
|
+
print(f"\n输入: 公司年收入 5 亿...")
|
|
88
|
+
for event in result.events:
|
|
89
|
+
if event.type == "final_output":
|
|
90
|
+
print(f" [{event.agent}] {event.data}")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# ============================================================
|
|
94
|
+
# 模式 C:循环执行 — 迭代优化
|
|
95
|
+
# ============================================================
|
|
96
|
+
|
|
97
|
+
print(f"\n{'=' * 50}")
|
|
98
|
+
print(" LoopAgent — 迭代优化循环")
|
|
99
|
+
print("=" * 50)
|
|
100
|
+
|
|
101
|
+
loop = LoopAgent(
|
|
102
|
+
name="improvement-loop",
|
|
103
|
+
max_iterations=3,
|
|
104
|
+
sub_agents=[
|
|
105
|
+
Agent(
|
|
106
|
+
name="writer",
|
|
107
|
+
instructions="你是一个文案写手。根据用户需求或上轮反馈,写一句广告语。只输出广告语本身。",
|
|
108
|
+
model="gpt-4o",
|
|
109
|
+
),
|
|
110
|
+
Agent(
|
|
111
|
+
name="critic",
|
|
112
|
+
instructions="你是一个文案评审。评估上面的广告语,如果已经很好则只输出'通过',否则给出简短的改进建议。",
|
|
113
|
+
model="gpt-4o",
|
|
114
|
+
),
|
|
115
|
+
],
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
result = Runner.run_sync(loop, input="为一款AI编程助手写一句吸引开发者的广告语")
|
|
119
|
+
print(f"\n输入: 为一款AI编程助手写广告语")
|
|
120
|
+
for event in result.events:
|
|
121
|
+
if event.type == "final_output":
|
|
122
|
+
print(f" [{event.agent}] {event.data}")
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"""
|
|
2
|
+
示例:三种运行方式对比 — 同步 / 异步 / 流式(标准版)
|
|
3
|
+
|
|
4
|
+
演示 Runner 的三种运行方式在同一个 Agent 上的用法差异。
|
|
5
|
+
|
|
6
|
+
运行前请设置环境变量:
|
|
7
|
+
export OPENAI_API_KEY="sk-..."
|
|
8
|
+
|
|
9
|
+
运行:
|
|
10
|
+
python examples/standard/07_sync_async_stream.py
|
|
11
|
+
"""
|
|
12
|
+
import asyncio
|
|
13
|
+
import sys
|
|
14
|
+
import os
|
|
15
|
+
import time
|
|
16
|
+
|
|
17
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", ".."))
|
|
18
|
+
|
|
19
|
+
from agentkit import Agent, Runner, function_tool
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# ===== 定义一个简单工具 =====
|
|
23
|
+
|
|
24
|
+
@function_tool
|
|
25
|
+
def get_weather(city: str) -> str:
|
|
26
|
+
"""获取指定城市的天气信息"""
|
|
27
|
+
return {"北京": "晴,25°C", "上海": "多云,22°C"}.get(city, f"{city}:暂无数据")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# ===== 创建 Agent =====
|
|
31
|
+
|
|
32
|
+
agent = Agent(
|
|
33
|
+
name="assistant",
|
|
34
|
+
instructions="你是一个简洁的中文助手。回答尽量简短。",
|
|
35
|
+
model="gpt-4o",
|
|
36
|
+
tools=[get_weather],
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# ============================================================
|
|
41
|
+
# 方式 1:同步运行 — Runner.run_sync()
|
|
42
|
+
# ============================================================
|
|
43
|
+
|
|
44
|
+
def demo_sync():
|
|
45
|
+
print("=" * 50)
|
|
46
|
+
print(" 方式 1:同步运行 — Runner.run_sync()")
|
|
47
|
+
print("=" * 50)
|
|
48
|
+
|
|
49
|
+
start = time.time()
|
|
50
|
+
result = Runner.run_sync(agent, input="北京今天天气如何?")
|
|
51
|
+
elapsed = time.time() - start
|
|
52
|
+
|
|
53
|
+
if result.success:
|
|
54
|
+
print(f" ✅ 回复: {result.final_output}")
|
|
55
|
+
else:
|
|
56
|
+
print(f" ❌ 错误: {result.error}")
|
|
57
|
+
print(f" ⏱️ 耗时: {elapsed:.1f}s")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# ============================================================
|
|
61
|
+
# 方式 2:异步运行 — await Runner.run()
|
|
62
|
+
# ============================================================
|
|
63
|
+
|
|
64
|
+
async def demo_async():
|
|
65
|
+
print(f"\n{'=' * 50}")
|
|
66
|
+
print(" 方式 2:异步运行 — await Runner.run()")
|
|
67
|
+
print("=" * 50)
|
|
68
|
+
|
|
69
|
+
start = time.time()
|
|
70
|
+
result = await Runner.run(agent, input="上海今天天气如何?")
|
|
71
|
+
elapsed = time.time() - start
|
|
72
|
+
|
|
73
|
+
if result.success:
|
|
74
|
+
print(f" ✅ 回复: {result.final_output}")
|
|
75
|
+
else:
|
|
76
|
+
print(f" ❌ 错误: {result.error}")
|
|
77
|
+
print(f" ⏱️ 耗时: {elapsed:.1f}s")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# ============================================================
|
|
81
|
+
# 方式 2b:异步并发 — 同时运行多个 Agent
|
|
82
|
+
# ============================================================
|
|
83
|
+
|
|
84
|
+
async def demo_async_concurrent():
|
|
85
|
+
print(f"\n{'=' * 50}")
|
|
86
|
+
print(" 方式 2b:异步并发 — 同时运行多个请求")
|
|
87
|
+
print("=" * 50)
|
|
88
|
+
|
|
89
|
+
queries = [
|
|
90
|
+
"1+1等于几?只回答数字",
|
|
91
|
+
"北京今天天气如何?",
|
|
92
|
+
"用一句话解释什么是 Python",
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
start = time.time()
|
|
96
|
+
results = await asyncio.gather(*[
|
|
97
|
+
Runner.run(agent, input=q) for q in queries
|
|
98
|
+
])
|
|
99
|
+
elapsed = time.time() - start
|
|
100
|
+
|
|
101
|
+
for q, r in zip(queries, results):
|
|
102
|
+
status = f"✅ {r.final_output}" if r.success else f"❌ {r.error}"
|
|
103
|
+
print(f" [{q[:15]:15s}] → {status}")
|
|
104
|
+
|
|
105
|
+
print(f" ⏱️ 3 个请求并发总耗时: {elapsed:.1f}s")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
# ============================================================
|
|
109
|
+
# 方式 3:流式运行 — Runner.run_streamed()
|
|
110
|
+
# ============================================================
|
|
111
|
+
|
|
112
|
+
async def demo_stream():
|
|
113
|
+
print(f"\n{'=' * 50}")
|
|
114
|
+
print(" 方式 3:流式运行 — Runner.run_streamed()")
|
|
115
|
+
print("=" * 50)
|
|
116
|
+
|
|
117
|
+
print(" 📡 实时事件流:")
|
|
118
|
+
|
|
119
|
+
start = time.time()
|
|
120
|
+
async for event in Runner.run_streamed(agent, input="北京今天天气如何?"):
|
|
121
|
+
elapsed = time.time() - start
|
|
122
|
+
if event.type == "llm_response":
|
|
123
|
+
has_tools = "有工具调用" if event.data.has_tool_calls else "纯文本"
|
|
124
|
+
print(f" [{elapsed:5.1f}s] 🤖 LLM 响应 ({has_tools})")
|
|
125
|
+
elif event.type == "tool_result":
|
|
126
|
+
tool_name = event.data.get("tool", "?")
|
|
127
|
+
tool_result = event.data.get("result", "")
|
|
128
|
+
print(f" [{elapsed:5.1f}s] 🔧 工具 {tool_name} → {tool_result}")
|
|
129
|
+
elif event.type == "final_output":
|
|
130
|
+
print(f" [{elapsed:5.1f}s] ✅ 最终输出: {event.data}")
|
|
131
|
+
else:
|
|
132
|
+
print(f" [{elapsed:5.1f}s] 📋 {event.type}: {str(event.data)[:60]}")
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
# ============================================================
|
|
136
|
+
# 主入口
|
|
137
|
+
# ============================================================
|
|
138
|
+
|
|
139
|
+
def run_all():
|
|
140
|
+
"""先同步跑一个,再 asyncio.run 跑异步的"""
|
|
141
|
+
|
|
142
|
+
print("🚀 AgentKit — 三种运行方式对比\n")
|
|
143
|
+
|
|
144
|
+
# 方式 1:同步(必须在 asyncio.run 之外调用)
|
|
145
|
+
demo_sync()
|
|
146
|
+
|
|
147
|
+
# 方式 2、2b、3:异步
|
|
148
|
+
async def async_demos():
|
|
149
|
+
await demo_async()
|
|
150
|
+
await demo_async_concurrent()
|
|
151
|
+
await demo_stream()
|
|
152
|
+
|
|
153
|
+
asyncio.run(async_demos())
|
|
154
|
+
|
|
155
|
+
print(f"\n{'=' * 50}")
|
|
156
|
+
print(" 全部演示完成 🎉")
|
|
157
|
+
print("=" * 50)
|
|
158
|
+
print("""
|
|
159
|
+
📝 总结:
|
|
160
|
+
run_sync() — 最简单,一行代码,适合脚本和测试
|
|
161
|
+
await run() — 异步核心,可并发执行多个请求
|
|
162
|
+
run_streamed() — 实时事件流,适合聊天 UI 和进度展示
|
|
163
|
+
|
|
164
|
+
⚠️ 注意:run_sync() 内部调用 asyncio.run(),因此不能在
|
|
165
|
+
已有事件循环中使用。如果你的代码已经是 async 的,
|
|
166
|
+
请直接用 await Runner.run()。
|
|
167
|
+
""")
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
if __name__ == "__main__":
|
|
171
|
+
run_all()
|