Skip to content

Commit 92a110d

Browse files
authored
Merge pull request #310 from ELK-milu/main
fix:修复base中创建知识库时直接将basemodel转为json时的报错问题
2 parents 42d2eb1 + fba6821 commit 92a110d

File tree

16 files changed

+284
-173
lines changed

16 files changed

+284
-173
lines changed

.gitignore

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,17 @@ cache
3535
.cursor
3636
.trae
3737
.pytest_cache
38-
*.nogit*
39-
*.private*
40-
*.local*
38+
39+
### (企业私有代码 - 仅忽略敏感配置,不忽略代码文件)
40+
# 移除了 *.private* 和 *_private 规则,允许 Git 本地管理
41+
# 通过 .git/info/exclude 或本地分支管理私有代码
4142
*.secret*
43+
*.nogit*
44+
# *.local* 保留用于本地配置文件
45+
*.local.py
46+
*.local.js
47+
*.local.yaml
48+
4249

4350
*.pdf
4451
src/data

docker-compose.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ services:
1515
- ./saves:/app/saves
1616
- ./test:/app/test
1717
- ./scripts:/app/scripts
18-
- ./.env :/app/.env
18+
- ./.env:/app/.env
1919
- ${MODEL_DIR:-./models}:/models # 使用默认值处理未定义的环境变量
2020
ports:
2121
- "5050:5050"
@@ -38,8 +38,8 @@ services:
3838
- MINIO_URI=${MINIO_URI:-http://milvus-minio:9000}
3939
- MODEL_DIR_IN_DOCKER=/models
4040
- RUNNING_IN_DOCKER=true
41-
- NO_PROXY=localhost,127.0.0.1,milvus,graph,milvus-minio,milvus-etcd-dev,etcd,minio,mineru,paddlex
42-
- no_proxy=localhost,127.0.0.1,milvus,graph,milvus-minio,milvus-etcd-dev,etcd,minio,mineru,paddlex
41+
- NO_PROXY=localhost,127.0.0.1,milvus,graph,milvus-minio,milvus-etcd-dev,etcd,minio,mineru,paddlex,api.siliconflow.cn
42+
- no_proxy=localhost,127.0.0.1,milvus,graph,milvus-minio,milvus-etcd-dev,etcd,minio,mineru,paddlex,api.siliconflow.cn
4343
# endregion api_envs
4444
command: uv run --no-dev uvicorn server.main:app --host 0.0.0.0 --port 5050 --reload
4545
restart: unless-stopped
@@ -145,7 +145,7 @@ services:
145145
- ETCD_SNAPSHOT_COUNT=50000
146146
volumes:
147147
- ./docker/volumes/milvus/etcd:/etcd
148-
command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd
148+
command: etcd -advertise-client-urls=http://etcd:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd
149149
healthcheck:
150150
test: ["CMD", "etcdctl", "endpoint", "health"]
151151
interval: 60s

server/main.py

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from starlette.middleware.base import BaseHTTPMiddleware
1010

1111
from server.routers import router
12-
from server.services.tasker import tasker
12+
from server.utils.lifespan import lifespan
1313
from server.utils.auth_middleware import is_public_path
1414
from server.utils.common_utils import setup_logging
1515

@@ -24,7 +24,7 @@
2424
_login_attempts: defaultdict[str, deque[float]] = defaultdict(deque)
2525
_attempt_lock = asyncio.Lock()
2626

27-
app = FastAPI()
27+
app = FastAPI(lifespan=lifespan)
2828
app.include_router(router, prefix="/api")
2929

3030
# CORS 设置
@@ -119,16 +119,5 @@ async def dispatch(self, request: Request, call_next):
119119
app.add_middleware(LoginRateLimitMiddleware)
120120
app.add_middleware(AuthMiddleware)
121121

122-
123-
@app.on_event("startup")
124-
async def start_tasker() -> None:
125-
await tasker.start()
126-
127-
128-
@app.on_event("shutdown")
129-
async def stop_tasker() -> None:
130-
await tasker.shutdown()
131-
132-
133122
if __name__ == "__main__":
134123
uvicorn.run(app, host="0.0.0.0", port=5050, threads=10, workers=10, reload=True)

server/routers/chat_router.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ async def get_agent(current_user: User = Depends(get_required_user)):
112112
metadata = yaml.safe_load(f)
113113
return {"agents": agents, "metadata": metadata}
114114

115-
115+
#TODO:[未完成]这个thread_id在前端是直接生成的1234,最好传入thread_id时做校验只允许uuid4
116116
@chat.post("/agent/{agent_id}")
117117
async def chat_agent(
118118
agent_id: str,
@@ -254,6 +254,7 @@ async def save_messages_from_langgraph_state(
254254
logger.error(f"Error saving messages from LangGraph state: {e}")
255255
logger.error(traceback.format_exc())
256256

257+
#TODO:[功能建议]针对需要人工审批后再执行的工具,可以使用langgraph的interrupt方法中断对话,等待用户输入后再使用command跳转回去
257258
async def stream_messages():
258259
# 代表服务端已经收到了请求
259260
yield make_chunk(status="init", meta=meta, msg=HumanMessage(content=query).model_dump())

server/utils/lifespan.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import asyncio
2+
from contextlib import asynccontextmanager
3+
4+
from fastapi import FastAPI
5+
6+
from server.services import tasker
7+
8+
#TODO:[已完成]使用lifespan进行统一生命周期管理
9+
10+
@asynccontextmanager
11+
async def lifespan(app: FastAPI):
12+
await tasker.start()
13+
"""FastAPI lifespan事件管理器"""
14+
yield
15+
await tasker.shutdown()

server/utils/singleton.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from threading import Lock
2+
3+
class SingletonMeta(type):
4+
"""
5+
This is a thread-safe implementation of Singleton.
6+
"""
7+
_instances = {}
8+
_lock: Lock = Lock()
9+
10+
def __call__(cls, *args, **kwargs):
11+
with cls._lock:
12+
if cls not in cls._instances:
13+
instance = super().__call__(*args, **kwargs)
14+
cls._instances[cls] = instance
15+
return cls._instances[cls]

src/agents/__init__.py

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import asyncio
2+
import importlib
3+
import inspect
4+
from pathlib import Path
25

3-
from .chatbot.graph import ChatbotAgent
4-
from .react.graph import ReActAgent
6+
from src.agents.common.base import BaseAgent
7+
from src.utils import logger
58

69

710
class AgentManager:
@@ -35,10 +38,51 @@ async def get_agents_info(self):
3538
agents = self.get_agents()
3639
return await asyncio.gather(*[a.get_info() for a in agents])
3740

41+
def auto_discover_agents(self):
42+
"""自动发现并注册 src/agents/ 下的所有智能体。
43+
44+
遍历 src/agents/ 目录下的所有子文件夹,如果子文件夹包含 __init__.py,
45+
则尝试从中导入 BaseAgent 的子类并注册。(使用自动导入的方式,支持私有agent)
46+
"""
47+
# 获取 agents 目录的路径
48+
agents_dir = Path(__file__).parent
49+
50+
# 遍历所有子目录
51+
for item in agents_dir.iterdir():
52+
logger.info(f"尝试导入模块:{item}")
53+
# 跳过非目录、common 目录、__pycache__ 等
54+
if not item.is_dir() or item.name.startswith("_") or item.name == "common":
55+
continue
56+
57+
# 检查是否有 __init__.py 文件
58+
init_file = item / "__init__.py"
59+
if not init_file.exists():
60+
logger.warning(f"{item} 不是一个有效的模块")
61+
continue
62+
63+
# 尝试导入模块
64+
try:
65+
module_name = f"src.agents.{item.name}"
66+
module = importlib.import_module(module_name)
67+
68+
# 查找模块中所有 BaseAgent 的子类
69+
for name, obj in inspect.getmembers(module):
70+
if (
71+
inspect.isclass(obj)
72+
and issubclass(obj, BaseAgent)
73+
and obj is not BaseAgent
74+
and obj.__module__.startswith(module_name)
75+
):
76+
logger.info(f"自动发现智能体: {obj.__name__} 来自 {item.name}")
77+
self.register_agent(obj)
78+
79+
except Exception as e:
80+
logger.warning(f"无法从 {item.name} 加载智能体: {e}")
81+
3882

3983
agent_manager = AgentManager()
40-
agent_manager.register_agent(ChatbotAgent)
41-
agent_manager.register_agent(ReActAgent)
84+
# 自动发现并注册所有智能体
85+
agent_manager.auto_discover_agents()
4286
agent_manager.init_all_agents()
4387

4488
__all__ = ["agent_manager"]

src/agents/chatbot/tools.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,20 @@
99
from src.storage.minio import upload_image_to_minio
1010
from src.utils import logger
1111

12-
13-
@tool
12+
#TODO:[已完成]修改了tool定义的示例,使用更符合langgraph调用的方式
13+
@tool(name_or_callable="全能计算器",description="可以对给定的2个数字选择进行加减乘除四种计算")
1414
def calculator(a: float, b: float, operation: str) -> float:
15-
"""Calculate two numbers. operation: add, subtract, multiply, divide"""
15+
"""
16+
可以对给定的2个数字选择进行加减乘除四种计算
17+
18+
Args:
19+
a: 第一个数字
20+
b: 第二个数字
21+
operation: 计算操作符号,可以是add,subtract,multiply,divide
22+
23+
Returns:
24+
float: 最终的计算结果
25+
"""
1626
try:
1727
if operation == "add":
1828
return a + b

src/agents/react/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .graph import ReActAgent
2+
3+
__all__ = ["ReActAgent"]

src/config/static/models.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,12 @@ class RerankerInfo(BaseModel):
142142
base_url="https://api.siliconflow.cn/v1/embeddings",
143143
api_key="SILICONFLOW_API_KEY",
144144
),
145+
"siliconflow/Pro/BAAI/bge-m3": EmbedModelInfo(
146+
name="Pro/BAAI/bge-m3",
147+
dimension=1024,
148+
base_url="https://api.siliconflow.cn/v1/embeddings",
149+
api_key="SILICONFLOW_API_KEY",
150+
),
145151
"siliconflow/Qwen/Qwen3-Embedding-0.6B": EmbedModelInfo(
146152
name="Qwen/Qwen3-Embedding-0.6B",
147153
dimension=1024,
@@ -179,6 +185,11 @@ class RerankerInfo(BaseModel):
179185
base_url="https://api.siliconflow.cn/v1/rerank",
180186
api_key="SILICONFLOW_API_KEY",
181187
),
188+
"siliconflow/Pro/BAAI/bge-reranker-v2-m3": RerankerInfo(
189+
name="Pro/BAAI/bge-reranker-v2-m3",
190+
base_url="https://api.siliconflow.cn/v1/rerank",
191+
api_key="SILICONFLOW_API_KEY",
192+
),
182193
"vllm/BAAI/bge-reranker-v2-m3": RerankerInfo(
183194
name="BAAI/bge-reranker-v2-m3",
184195
base_url="http://localhost:8000/v1/rerank",

0 commit comments

Comments
 (0)