133 lines
5.2 KiB
Python
133 lines
5.2 KiB
Python
"""
|
|
OUT.py 的调用链 demo —— 跑通 agent_init → leader 派活 → 各 special agent 干活 这一整套流程。
|
|
|
|
前置条件:
|
|
1. DeerFlow 后端在 http://127.0.0.1:8001 在跑
|
|
2. OUT.py 已经 `python -m uvicorn OUT:app --host 0.0.0.0 --port 8095` 起好
|
|
3. 下面 SUB_AGENT_NAMES 里的 agent 已经在 DeerFlow 里创建好(/api/agents 能查到)
|
|
|
|
直接 `python demo_call.py` 即可。
|
|
"""
|
|
import asyncio
|
|
import json
|
|
|
|
import httpx
|
|
|
|
# ============ 改这里 ============
|
|
OUT_BASE = "http://127.0.0.1:8095"
|
|
|
|
# 已经在 DeerFlow 里建好的子 agent 名字 (会被 OUT.py 强制 lowercase)
|
|
SUB_AGENT_NAMES = [
|
|
"us-intelligence-gathering-agent",
|
|
"taiwan-intelligence-gathering-agent",
|
|
]
|
|
|
|
# 总控 agent 名字 —— OUT.py 会现场创建它,所以填一个新名字即可 (hyphen-case)
|
|
MAIN_AGENT_NAME = "demo-coordinator"
|
|
|
|
# 用户提问 —— 总控会基于此派活
|
|
USER_QUESTION = "对比中美两国 2024 年在 AI 监管政策上的差异"
|
|
|
|
# leader 阶段命中即停的 skill 名字单 (OUT.py 用 agent_orchestration 作为派活信号)
|
|
SKILL_STOP_NAMES = ["agent_orchestration"]
|
|
# ================================
|
|
|
|
|
|
async def call_agent_init() -> tuple[str, dict[str, str]]:
|
|
"""步骤 1: 初始化 —— 拿回 thread_ids 字典 {agent_name → thread_id}."""
|
|
print(">>> [1/3] POST /agent_init")
|
|
async with httpx.AsyncClient(timeout=300.0) as client:
|
|
r = await client.post(
|
|
f"{OUT_BASE}/agent_init",
|
|
json={
|
|
"agent_names": SUB_AGENT_NAMES,
|
|
"main_agent_name": MAIN_AGENT_NAME,
|
|
},
|
|
)
|
|
r.raise_for_status()
|
|
body = r.json()
|
|
main_name = body["main_agent_name"]
|
|
thread_ids = body["thread_ids"]
|
|
print(f" main_agent_name = {main_name}")
|
|
print(f" thread_ids = {json.dumps(thread_ids, ensure_ascii=False, indent=2)}")
|
|
return main_name, thread_ids
|
|
|
|
|
|
async def stream_generate(payload: dict) -> object | None:
|
|
"""通用 SSE 消费:边收边打印,最后返回 OUT.py 自己 yield 的 {'status': ...} 里的 status 字段."""
|
|
final_status = None
|
|
async with httpx.AsyncClient(timeout=None) as client:
|
|
async with client.stream("POST", f"{OUT_BASE}/generate_mul_agent", json=payload) as resp:
|
|
print(f" HTTP {resp.status_code}")
|
|
if resp.status_code != 200:
|
|
err = await resp.aread()
|
|
raise RuntimeError(f"OUT.py /generate_mul_agent failed: {err.decode('utf-8', 'replace')[:500]}")
|
|
|
|
async for line in resp.aiter_lines():
|
|
if not line:
|
|
continue
|
|
# OUT.py 把 DeerFlow 的原始 SSE 流直接转发,自己最后会再 yield 一行
|
|
# `data: {"status": ...}\n\n`。两边都以 `data:` 开头,我们都尝试 JSON parse
|
|
# 一下,能解析成 {"status": ...} 的就是 OUT.py 的终态。
|
|
if line.startswith("data:"):
|
|
body_text = line[5:].strip()
|
|
try:
|
|
obj = json.loads(body_text)
|
|
except json.JSONDecodeError:
|
|
continue
|
|
if isinstance(obj, dict) and "status" in obj:
|
|
final_status = obj["status"]
|
|
# 想看上游 DeerFlow 的完整流,把下面打开即可
|
|
# else:
|
|
# print(" raw:", line[:200])
|
|
return final_status
|
|
|
|
|
|
async def call_leader(main_agent_name: str, thread_ids: dict[str, str]) -> list[list[str]]:
|
|
"""步骤 2: leader 阶段 —— 总控读完用户问题,产出派活清单."""
|
|
print(f"\n>>> [2/3] POST /generate_mul_agent (leader, agent={main_agent_name})")
|
|
status = await stream_generate(
|
|
{
|
|
"agent_type": "leader",
|
|
"d_agent_thread_id": thread_ids,
|
|
"agent_name": main_agent_name,
|
|
"new_message": USER_QUESTION,
|
|
"skill_stop_names": SKILL_STOP_NAMES,
|
|
}
|
|
)
|
|
dispatch = status or []
|
|
print(f" 派活清单 = {json.dumps(dispatch, ensure_ascii=False, indent=2)}")
|
|
return dispatch
|
|
|
|
|
|
async def call_specials(thread_ids: dict[str, str], dispatch: list[list[str]]) -> None:
|
|
"""步骤 3: 把派活清单里每一项交给对应子 agent 跑."""
|
|
if not dispatch:
|
|
print("\n>>> [3/3] 总控没派出任何任务,直接结束。")
|
|
return
|
|
for idx, item in enumerate(dispatch, 1):
|
|
agent_name, task_text = item[0], item[1]
|
|
print(f"\n>>> [3/3] ({idx}/{len(dispatch)}) POST /generate_mul_agent (special, agent={agent_name})")
|
|
print(f" task = {task_text[:120]}{'...' if len(task_text) > 120 else ''}")
|
|
result = await stream_generate(
|
|
{
|
|
"agent_type": "special",
|
|
"d_agent_thread_id": thread_ids,
|
|
"agent_name": agent_name,
|
|
"new_message": task_text,
|
|
"skill_stop_names": [],
|
|
}
|
|
)
|
|
print(f" 完成: {result}")
|
|
|
|
|
|
async def main() -> None:
|
|
main_agent_name, thread_ids = await call_agent_init()
|
|
dispatch = await call_leader(main_agent_name, thread_ids)
|
|
await call_specials(thread_ids, dispatch)
|
|
print("\n✅ demo 跑完")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|