Files
Simon d9be75a98f feat: Phase 5 — AI Research Agent(受控工具白名单 + LLM 编排 + API)
- agent/tools.py:Tool 元数据(JSON Schema)+ 白名单调用(异常转可读反馈,不中断对话)
- agent/tools_impl.py:6 个受控工具 search_stocks / get_market_data / test_factor / run_backtest / get_experiment / compare_experiments —— 全部只读经 Job/Experiment 链路,研究自动归档;无 shell/任意执行/写删数据能力
- agent/llm.py:LLMClient 抽象 + OpenAI 兼容客户端(LLM_API_KEY/LLM_BASE_URL/LLM_MODEL 走 .env,未配置给出引导提示)+ 研究纪律 system prompt(反过拟合/样本外/成本)
- agent/service.py:编排循环(tool/final JSON 决策 → 执行 → 回喂 → 结论),轮次上限兜底,未知工具拒绝
- /api/agent/chat;httpx 移至主依赖;Job 默认工厂抽取(api/agent/executor 复用)
- 测试 6 项(白名单无 shell、完整研究循环产出、未知工具拒绝、轮次兜底),全量 79 passed / ruff clean
2026-09-06 17:22:05 +08:00

41 lines
1.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""AI Research Agent API(Phase 5)。
POST /api/agent/chat {message} → {reply, actions:[{tool,args,output}]}
未配置 LLM Key 时返回 400 引导(不会崩溃)。
"""
from __future__ import annotations
from typing import Annotated
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel, Field
from app.agent.llm import LLMClient, build_llm_from_settings
from app.agent.service import AgentService
router = APIRouter(prefix="/agent", tags=["agent"])
class AgentChatRequest(BaseModel):
message: str = Field(min_length=1, max_length=2000)
def _llm_or_raise() -> LLMClient:
llm = build_llm_from_settings()
if llm is None:
raise HTTPException(
status_code=400,
detail="未配置 LLM:请在根目录 .env 中设置 LLM_API_KEY(可选 LLM_BASE_URL / LLM_MODEL),"
"参考 .env.example 与 AGENT.md §33",
)
return llm
@router.post("/chat", summary="与 AI 研究助手对话(受控工具)")
def agent_chat(
body: AgentChatRequest,
llm: Annotated[LLMClient, Depends(_llm_or_raise)],
) -> dict:
return AgentService(llm).chat(body.message)