mirror of
https://gitee.com/wanwujie/deer-flow
synced 2026-04-02 22:02:13 +08:00
feat: support function factory (#4)
This commit is contained in:
75
backend/debug.py
Normal file
75
backend/debug.py
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
"""
|
||||||
|
Debug script for lead_agent.
|
||||||
|
Run this file directly in VS Code with breakpoints.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
1. Set breakpoints in agent.py or other files
|
||||||
|
2. Press F5 or use "Run and Debug" panel
|
||||||
|
3. Input messages in the terminal to interact with the agent
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Ensure we can import from src
|
||||||
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
# Load environment variables
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from langchain_core.messages import HumanMessage
|
||||||
|
|
||||||
|
from src.agents import make_lead_agent
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
# Create agent with default config
|
||||||
|
config = {
|
||||||
|
"configurable": {
|
||||||
|
"thread_id": "debug-thread-001",
|
||||||
|
"thinking_enabled": True,
|
||||||
|
# Uncomment to use a specific model
|
||||||
|
"model_name": "doubao-seed-1.8",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
agent = make_lead_agent(config)
|
||||||
|
|
||||||
|
print("=" * 50)
|
||||||
|
print("Lead Agent Debug Mode")
|
||||||
|
print("Type 'quit' or 'exit' to stop")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
user_input = input("\nYou: ").strip()
|
||||||
|
if not user_input:
|
||||||
|
continue
|
||||||
|
if user_input.lower() in ("quit", "exit"):
|
||||||
|
print("Goodbye!")
|
||||||
|
break
|
||||||
|
|
||||||
|
# Invoke the agent
|
||||||
|
state = {"messages": [HumanMessage(content=user_input)]}
|
||||||
|
result = await agent.ainvoke(state, config=config, context={"thread_id": "debug-thread-001"})
|
||||||
|
|
||||||
|
# Print the response
|
||||||
|
if result.get("messages"):
|
||||||
|
last_message = result["messages"][-1]
|
||||||
|
print(f"\nAgent: {last_message.content}")
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\nInterrupted. Goodbye!")
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\nError: {e}")
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
@@ -3,6 +3,6 @@
|
|||||||
"dependencies": ["."],
|
"dependencies": ["."],
|
||||||
"env": ".env",
|
"env": ".env",
|
||||||
"graphs": {
|
"graphs": {
|
||||||
"lead_agent": "src.agents:lead_agent"
|
"lead_agent": "src.agents:make_lead_agent"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from .lead_agent import lead_agent
|
from .lead_agent import make_lead_agent
|
||||||
from .thread_state import SandboxState, ThreadState
|
from .thread_state import SandboxState, ThreadState
|
||||||
|
|
||||||
__all__ = ["lead_agent", "SandboxState", "ThreadState"]
|
__all__ = ["make_lead_agent", "SandboxState", "ThreadState"]
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
from .agent import lead_agent
|
from .agent import make_lead_agent
|
||||||
|
|
||||||
__all__ = ["lead_agent"]
|
__all__ = ["make_lead_agent"]
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from langchain.agents import create_agent
|
from langchain.agents import create_agent
|
||||||
|
from langchain_core.runnables import RunnableConfig
|
||||||
|
|
||||||
from src.agents.lead_agent.prompt import apply_prompt_template
|
from src.agents.lead_agent.prompt import apply_prompt_template
|
||||||
from src.agents.middlewares.thread_data_middleware import ThreadDataMiddleware
|
from src.agents.middlewares.thread_data_middleware import ThreadDataMiddleware
|
||||||
@@ -11,10 +12,15 @@ from src.tools import get_available_tools
|
|||||||
# ThreadDataMiddleware must be before SandboxMiddleware to ensure thread_id is available
|
# ThreadDataMiddleware must be before SandboxMiddleware to ensure thread_id is available
|
||||||
middlewares = [ThreadDataMiddleware(), SandboxMiddleware(), TitleMiddleware()]
|
middlewares = [ThreadDataMiddleware(), SandboxMiddleware(), TitleMiddleware()]
|
||||||
|
|
||||||
lead_agent = create_agent(
|
|
||||||
model=create_chat_model(thinking_enabled=True),
|
def make_lead_agent(config: RunnableConfig):
|
||||||
tools=get_available_tools(),
|
thinking_enabled = config.get("configurable", {}).get("thinking_enabled", True)
|
||||||
middleware=middlewares,
|
model_name = config.get("configurable", {}).get("model_name")
|
||||||
system_prompt=apply_prompt_template(),
|
print(f"thinking_enabled: {thinking_enabled}, model_name: {model_name}")
|
||||||
state_schema=ThreadState,
|
return create_agent(
|
||||||
)
|
model=create_chat_model(name=model_name, thinking_enabled=thinking_enabled),
|
||||||
|
tools=get_available_tools(),
|
||||||
|
middleware=middlewares,
|
||||||
|
system_prompt=apply_prompt_template(),
|
||||||
|
state_schema=ThreadState,
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import os
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
SYSTEM_PROMPT = f"""
|
SYSTEM_PROMPT = f"""
|
||||||
|
|||||||
@@ -71,8 +71,9 @@ class ThreadDataMiddleware(AgentMiddleware[ThreadDataMiddlewareState]):
|
|||||||
@override
|
@override
|
||||||
def before_agent(self, state: ThreadDataMiddlewareState, runtime: Runtime) -> dict | None:
|
def before_agent(self, state: ThreadDataMiddlewareState, runtime: Runtime) -> dict | None:
|
||||||
# Generate new thread ID and create directories
|
# Generate new thread ID and create directories
|
||||||
print(runtime.context)
|
thread_id = runtime.context.get("thread_id")
|
||||||
thread_id = runtime.context["thread_id"]
|
if thread_id is None:
|
||||||
|
raise ValueError("Thread ID is required in the context")
|
||||||
paths = self._create_thread_directories(thread_id)
|
paths = self._create_thread_directories(thread_id)
|
||||||
print(f"Created thread data directories for thread {thread_id}")
|
print(f"Created thread data directories for thread {thread_id}")
|
||||||
|
|
||||||
|
|||||||
@@ -168,14 +168,16 @@ def read_file_tool(
|
|||||||
runtime: ToolRuntime[ContextT, ThreadState],
|
runtime: ToolRuntime[ContextT, ThreadState],
|
||||||
description: str,
|
description: str,
|
||||||
path: str,
|
path: str,
|
||||||
view_range: tuple[int, int] | None = None,
|
start_line: int | None = None,
|
||||||
|
end_line: int | None = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Read the contents of a text file.
|
"""Read the contents of a text file. Use this to examine source code, configuration files, logs, or any text-based file.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
description: Explain why you are viewing this file in short words. ALWAYS PROVIDE THIS PARAMETER FIRST.
|
description: Explain why you are reading this file in short words. ALWAYS PROVIDE THIS PARAMETER FIRST.
|
||||||
path: The **absolute** path to the file to read.
|
path: The **absolute** path to the file to read.
|
||||||
view_range: The range of lines to view. The range is inclusive and starts at 1. For example, (1, 10) will view the first 10 lines of the file.
|
start_line: Optional starting line number (1-indexed, inclusive). Use with end_line to read a specific range.
|
||||||
|
end_line: Optional ending line number (1-indexed, inclusive). Use with start_line to read a specific range.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
sandbox = sandbox_from_runtime(runtime)
|
sandbox = sandbox_from_runtime(runtime)
|
||||||
@@ -185,9 +187,8 @@ def read_file_tool(
|
|||||||
content = sandbox.read_file(path)
|
content = sandbox.read_file(path)
|
||||||
if not content:
|
if not content:
|
||||||
return "(empty)"
|
return "(empty)"
|
||||||
if view_range:
|
if start_line is not None and end_line is not None:
|
||||||
start, end = view_range
|
content = "\n".join(content.splitlines()[start_line - 1 : end_line])
|
||||||
content = "\n".join(content.splitlines()[start - 1 : end])
|
|
||||||
return content
|
return content
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return f"Error: {e}"
|
return f"Error: {e}"
|
||||||
|
|||||||
@@ -13,5 +13,34 @@
|
|||||||
"workspace": "deer-flow"
|
"workspace": "deer-flow"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"launch": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Debug Lead Agent",
|
||||||
|
"type": "debugpy",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/backend/debug.py",
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
"cwd": "${workspaceFolder}/backend",
|
||||||
|
"env": {
|
||||||
|
"PYTHONPATH": "${workspaceFolder}/backend"
|
||||||
|
},
|
||||||
|
"justMyCode": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Debug Lead Agent (justMyCode)",
|
||||||
|
"type": "debugpy",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/backend/debug.py",
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
"cwd": "${workspaceFolder}/backend",
|
||||||
|
"env": {
|
||||||
|
"PYTHONPATH": "${workspaceFolder}/backend"
|
||||||
|
},
|
||||||
|
"justMyCode": true
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user