mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-28 19:58:11 +08:00
feat(agent): Go port — canvas engine, 22 components, DSL v2, 13 endpoints (#15952)
Ports the agent canvas subsystem from Python to Go.
## What's included
### Canvas Engine (Phase 0/1)
- State engine, scheduler, variable resolver, Redis checkpoint store,
cancel protocol
- **209 tests** across canvas / component / io packages
### 22 Components (P0–P4)
| Tier | Components |
|---|---|
| P0 T1+T2+T3 | LLM, Agent, ExitLoop, Switch, Categorize, Begin,
Message, Invoke |
| P1 T3 | VariableAggregator, VariableAssigner, StringTransform,
ListOperations, DataOperations |
| P2 T3 | Iteration, IterationItem, Loop, LoopItem |
| P3 T3 | UserFillUp, Fillup |
| P4 T5 | Browser, ExcelProcessor, DocsGenerator |
### DSL v2 Schema (Phase 2.5)
- Typed v2 in-memory model with v1-to-v2 auto-detect converter
- v1 legacy field stripping per plan §2.11.7
### HTTP Endpoints & Bug Fixes (Plans PR1–PR3)
- **DELETE SQL bug fix**: gorm v2 `Where("id = ?", id).Delete(...)`
pattern
- **CreateAgent validation**: title/DSL required, duplicate check, 103
envelope
- **13 new endpoints**: templates, prompts, tags, sessions CRUD,
chat/completions (SSE + non-stream stubs), rerun, test_db_connection,
logs, webhook/logs
- **756 Go unit tests** (745 → 756, +18)
- **17 → 0 Python integration test failures** (test_agents.py +
test_session_management/)
### Tools
21 eino tools: HTTPHelper, search tools, financial/data tools, mandatory
stubs
### Infrastructure
OTel observability, NATS message queue, DeepDoc gRPC client, SSRF
guards, IDOR mitigation
This commit is contained in:
453
internal/agent/dsl/testdata/complex_v1.json
vendored
Normal file
453
internal/agent/dsl/testdata/complex_v1.json
vendored
Normal file
@@ -0,0 +1,453 @@
|
||||
{
|
||||
"components": {
|
||||
"Begin:7d83abf3b4f611efa3c40242ac120002": {
|
||||
"downstream": ["Categorize:11111111aaaa0001aaaa0001aaaa0001"],
|
||||
"upstream": [],
|
||||
"obj": {
|
||||
"component_name": "Begin",
|
||||
"params": {
|
||||
"mode": "conversational",
|
||||
"enablePrologue": true,
|
||||
"prologue": "Hi! I'm your multi-source research copilot. Ask me anything and I'll dig through our knowledge base, score the evidence, and synthesize a sourced answer.",
|
||||
"inputs": [
|
||||
{"name": "query", "type": "string", "value": "{sys.query}"},
|
||||
{"name": "user_id", "type": "string", "value": "{sys.user_id}"},
|
||||
{"name": "session_id", "type": "string", "value": "{sys.session_id}"}
|
||||
],
|
||||
"outputs": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"Categorize:11111111aaaa0001aaaa0001aaaa0001": {
|
||||
"downstream": ["Switch:22222222bbbb0001bbbb0001bbbb0001"],
|
||||
"obj": {
|
||||
"component_name": "Categorize",
|
||||
"params": {
|
||||
"category_description": {
|
||||
"research": {
|
||||
"to": "Switch:22222222bbbb0001bbbb0001bbbb0001",
|
||||
"description": "User is asking a research question, a how-to, a comparison, or wants a sourced answer.",
|
||||
"examples": [
|
||||
"What is retrieval-augmented generation?",
|
||||
"Compare LoRA vs full fine-tuning",
|
||||
"Summarize the latest papers on agent loops"
|
||||
]
|
||||
},
|
||||
"clarify": {
|
||||
"to": "UserFillup:cccccccc00010001cccc00010001cccc0001",
|
||||
"description": "User's intent is ambiguous and we need them to disambiguate.",
|
||||
"examples": ["explain that", "tell me about it", "go on"]
|
||||
},
|
||||
"decline": {
|
||||
"to": "Message:00000000eeee0001eeee0001eeee0001",
|
||||
"description": "User is asking for content we cannot provide (e.g. medical diagnosis, legal advice, or unrelated chitchat).",
|
||||
"examples": ["diagnose my symptoms", "should I sue my employer", "hi how are you"]
|
||||
}
|
||||
},
|
||||
"llm_id": "gpt-4o-mini",
|
||||
"query": "{Begin:7d83abf3b4f611efa3c40242ac120002@query}",
|
||||
"message_history_window_size": 5,
|
||||
"temperature": 0.0,
|
||||
"outputs": [{"name": "intent", "type": "string"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Switch:22222222bbbb0001bbbb0001bbbb0001": {
|
||||
"downstream": [
|
||||
"Agent:33333333cccc0001cccc0001cccc0001",
|
||||
"UserFillup:cccccccc00010001cccc00010001cccc0001",
|
||||
"Message:00000000eeee0001eeee0001eeee0001"
|
||||
],
|
||||
"obj": {
|
||||
"component_name": "Switch",
|
||||
"params": {
|
||||
"logical_operator": "or",
|
||||
"conditions": [
|
||||
{
|
||||
"cpn_id": "Categorize:11111111aaaa0001aaaa0001aaaa0001",
|
||||
"operator": "=",
|
||||
"value": "research",
|
||||
"to": "Agent:33333333cccc0001cccc0001cccc0001"
|
||||
}
|
||||
],
|
||||
"end_cpn_ids": [
|
||||
"UserFillup:cccccccc00010001cccc00010001cccc0001",
|
||||
"Message:00000000eeee0001eeee0001eeee0001"
|
||||
],
|
||||
"operators": [
|
||||
"contains", "not contains", "start with", "end with",
|
||||
"empty", "not empty", "=", "≠", ">", "<", "≥", "≤"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"UserFillup:cccccccc00010001cccc00010001cccc0001": {
|
||||
"downstream": ["Message:00000000eeee0002eeee0002eeee0002"],
|
||||
"obj": {
|
||||
"component_name": "UserFillup",
|
||||
"params": {
|
||||
"inputs": [
|
||||
{
|
||||
"name": "intent",
|
||||
"type": "select",
|
||||
"options": ["research", "chitchat", "support"],
|
||||
"value": "research"
|
||||
},
|
||||
{
|
||||
"name": "clarifying_question",
|
||||
"type": "string",
|
||||
"value": "Could you tell me a bit more about what you want to know? I can answer research questions, summarize documents, or compare approaches."
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{"name": "intent", "type": "string"},
|
||||
{"name": "clarifying_question", "type": "string"}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Message:00000000eeee0001eeee0001eeee0001": {
|
||||
"downstream": [],
|
||||
"obj": {
|
||||
"component_name": "Message",
|
||||
"params": {
|
||||
"content": "I'm sorry, but I can't help with that kind of request. I can answer research questions, summarize documents, or compare approaches — feel free to ask one of those!",
|
||||
"outputs": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"Message:00000000eeee0002eeee0002eeee0002": {
|
||||
"downstream": [],
|
||||
"obj": {
|
||||
"component_name": "Message",
|
||||
"params": {
|
||||
"content": "Got it. To help me route your question, please share a clarifying question via the form.",
|
||||
"outputs": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"Agent:33333333cccc0001cccc0001cccc0001": {
|
||||
"downstream": ["Loop:dddddddd0001000100010001000100010001"],
|
||||
"obj": {
|
||||
"component_name": "Agent",
|
||||
"params": {
|
||||
"description": "Decomposes the user's research question into 1-5 self-contained sub-questions that the loop can answer one at a time.",
|
||||
"llm_id": "gpt-4o",
|
||||
"prompts": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are a meticulous research planner. Decompose the user's question into 1-5 self-contained sub-questions that can each be answered by retrieving from a knowledge base. Output JSON: {\"sub_questions\": [\"...\", \"...\"]}."
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "{Begin:7d83abf3b4f611efa3c40242ac120002@query}"
|
||||
}
|
||||
],
|
||||
"tools": ["retrieval"],
|
||||
"memory": [
|
||||
{"role": "user", "limit": 6, "session_only": true}
|
||||
],
|
||||
"cite": false,
|
||||
"max_steps": 4,
|
||||
"delay_after_error": 2,
|
||||
"exception_method": "default",
|
||||
"exception_default_value": "{\"sub_questions\": [\"{Begin:7d83abf3b4f611efa3c40242ac120002@query}\"]}",
|
||||
"exception_goto": "Loop:dddddddd0001000100010001000100010001",
|
||||
"exception_comment": "fallback to a single-sub-question loop with the original query",
|
||||
"outputs": [
|
||||
{"name": "sub_questions", "type": "json"}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Loop:dddddddd0001000100010001000100010001": {
|
||||
"downstream": ["Iteration:7777777700010001000100010001aaaa0001"],
|
||||
"obj": {
|
||||
"component_name": "Loop",
|
||||
"params": {
|
||||
"loop_variables": [
|
||||
{"name": "accumulated_evidence", "source": "literal", "value": "[]"}
|
||||
],
|
||||
"loop_termination_condition": [
|
||||
{
|
||||
"variable": "accumulated_evidence",
|
||||
"operator": "≥",
|
||||
"value": "5"
|
||||
}
|
||||
],
|
||||
"maximum_loop_count": 5,
|
||||
"outputs": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"LoopItem:eeeeeeee00010001000100010001bbbb0001": {
|
||||
"downstream": ["Retrieval:555555550001000100010001eeee0001"],
|
||||
"obj": {
|
||||
"component_name": "LoopItem",
|
||||
"params": {
|
||||
"outputs": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"Retrieval:555555550001000100010001eeee0001": {
|
||||
"downstream": ["LLM:444444440001000100010001dddd0001"],
|
||||
"obj": {
|
||||
"component_name": "Retrieval",
|
||||
"params": {
|
||||
"kb_ids": ["kb_research_2024", "kb_company_wiki", "kb_industry_reports"],
|
||||
"top_k": 10,
|
||||
"rerank_id": "bge-reranker-v2-m3",
|
||||
"empty_response": "No matching documents were found.",
|
||||
"keywords": [
|
||||
"{Agent:33333333cccc0001cccc0001cccc0001@sub_questions}"
|
||||
],
|
||||
"query": "{Begin:7d83abf3b4f611efa3c40242ac120002@query}",
|
||||
"outputs": [{"name": "chunks", "type": "json"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"LLM:444444440001000100010001dddd0001": {
|
||||
"downstream": ["Categorize:11111111aaaa0002aaaa0002aaaa0002"],
|
||||
"obj": {
|
||||
"component_name": "LLM",
|
||||
"params": {
|
||||
"model": "gpt-4o-mini",
|
||||
"temperature": 0.0,
|
||||
"system": "You are a relevance scorer. For each chunk, output a JSON object {\"idx\": <int>, \"score\": <0.0-1.0>, \"reason\": \"<short>\"}.",
|
||||
"prompt": "Score the relevance of each chunk to the user's question.\n\nQuestion: {Begin:7d83abf3b4f611efa3c40242ac120002@query}\n\nChunks: {Retrieval:555555550001000100010001eeee0001@chunks}",
|
||||
"max_tokens": 1024,
|
||||
"outputs": [{"name": "scored_chunks", "type": "json"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Categorize:11111111aaaa0002aaaa0002aaaa0002": {
|
||||
"downstream": ["Switch:22222222bbbb0002bbbb0002bbbb0002"],
|
||||
"obj": {
|
||||
"component_name": "Categorize",
|
||||
"params": {
|
||||
"category_description": {
|
||||
"high_relevance": {
|
||||
"to": "Switch:22222222bbbb0002bbbb0002bbbb0002",
|
||||
"description": "The retrieved chunk is highly relevant to the user's question (score ≥ 0.7).",
|
||||
"examples": ["directly answers the question", "contains the exact term the user asked about"]
|
||||
},
|
||||
"low_relevance": {
|
||||
"to": "VariableAggregator:666666660001000100010001ffff0001",
|
||||
"description": "The retrieved chunk is off-topic or redundant (score < 0.3).",
|
||||
"examples": ["tangentially mentions the topic", "duplicates another chunk"]
|
||||
}
|
||||
},
|
||||
"llm_id": "gpt-4o-mini",
|
||||
"query": "{LLM:444444440001000100010001dddd0001@scored_chunks}",
|
||||
"message_history_window_size": 1,
|
||||
"temperature": 0.0,
|
||||
"outputs": [{"name": "relevance", "type": "string"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Switch:22222222bbbb0002bbbb0002bbbb0002": {
|
||||
"downstream": ["VariableAggregator:666666660001000100010001ffff0001"],
|
||||
"obj": {
|
||||
"component_name": "Switch",
|
||||
"params": {
|
||||
"logical_operator": "or",
|
||||
"conditions": [
|
||||
{
|
||||
"cpn_id": "Categorize:11111111aaaa0002aaaa0002aaaa0002",
|
||||
"operator": "contains",
|
||||
"value": "high_relevance",
|
||||
"to": "VariableAggregator:666666660001000100010001ffff0001"
|
||||
}
|
||||
],
|
||||
"end_cpn_ids": ["VariableAggregator:666666660001000100010001ffff0001"],
|
||||
"operators": [
|
||||
"contains", "not contains", "=", "≠"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"VariableAggregator:666666660001000100010001ffff0001": {
|
||||
"downstream": ["Iteration:7777777700010001000100010001aaaa0001"],
|
||||
"obj": {
|
||||
"component_name": "VariableAggregator",
|
||||
"params": {
|
||||
"groups": [
|
||||
{
|
||||
"group_id": "evidence_group",
|
||||
"group_name": "evidence",
|
||||
"llm_id": "gpt-4o-mini",
|
||||
"format": "{Retrieval:555555550001000100010001eeee0001@chunks}",
|
||||
"refusal_answer": "no evidence",
|
||||
"output": {
|
||||
"value": {"type": "collected", "value": "evidence"}
|
||||
}
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{"name": "evidence", "type": "json"}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Iteration:7777777700010001000100010001aaaa0001": {
|
||||
"downstream": ["LLM:444444440002000200020002dddd0002"],
|
||||
"obj": {
|
||||
"component_name": "Iteration",
|
||||
"params": {
|
||||
"items_ref": "VariableAggregator:666666660001000100010001ffff0001@evidence",
|
||||
"variable": {
|
||||
"chunk_id": "",
|
||||
"chunk_text": ""
|
||||
},
|
||||
"outputs": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"IterationItem:8888888800010001000100010001bbbb0001": {
|
||||
"downstream": ["VariableAggregator:666666660002000200020002ffff0002"],
|
||||
"obj": {
|
||||
"component_name": "IterationItem",
|
||||
"params": {
|
||||
"outputs": [
|
||||
{"name": "excerpt", "type": "string"}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"VariableAggregator:666666660002000200020002ffff0002": {
|
||||
"downstream": ["LLM:444444440002000200020002dddd0002"],
|
||||
"obj": {
|
||||
"component_name": "VariableAggregator",
|
||||
"params": {
|
||||
"groups": [
|
||||
{
|
||||
"group_id": "ranked_group",
|
||||
"group_name": "ranked_excerpts",
|
||||
"llm_id": "gpt-4o-mini",
|
||||
"format": "{IterationItem:8888888800010001000100010001bbbb0001@excerpt}",
|
||||
"refusal_answer": "no excerpt",
|
||||
"output": {
|
||||
"value": {"type": "collected", "value": "ranked_excerpts"}
|
||||
}
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{"name": "ranked_excerpts", "type": "json"}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"LLM:444444440002000200020002dddd0002": {
|
||||
"downstream": ["CodeExec:bbbbbbbb0001000100010001cccc0001"],
|
||||
"obj": {
|
||||
"component_name": "LLM",
|
||||
"params": {
|
||||
"model": "deepseek-chat",
|
||||
"temperature": 0.2,
|
||||
"system": "You are a careful synthesizer. Combine the ranked excerpts into a sourced answer. Cite the chunk id for every claim.",
|
||||
"prompt": "Question: {Begin:7d83abf3b4f611efa3c40242ac120002@query}\n\nRanked excerpts: {VariableAggregator:666666660002000200020002ffff0002@ranked_excerpts}",
|
||||
"max_tokens": 1024,
|
||||
"outputs": [
|
||||
{"name": "draft_answer", "type": "string"},
|
||||
{"name": "citations", "type": "json"}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"CodeExec:bbbbbbbb0001000100010001cccc0001": {
|
||||
"downstream": ["Switch:22222222bbbb0003bbbb0003bbbb0003"],
|
||||
"obj": {
|
||||
"component_name": "CodeExec",
|
||||
"params": {
|
||||
"script": "import json, sys\ndraft = sys.argv[1]\ncitations = json.loads(sys.argv[2])\n# Validate: every claim in the draft must reference a real citation id.\nok = all(c.get('id') for c in citations) and len(citations) > 0\nprint(json.dumps({\"ok\": ok, \"citation_count\": len(citations), \"draft_len\": len(draft)}))",
|
||||
"lang": "python",
|
||||
"arguments": [
|
||||
"{LLM:444444440002000200020002dddd0002@draft_answer}",
|
||||
"{LLM:444444440002000200020002dddd0002@citations}"
|
||||
],
|
||||
"outputs": [
|
||||
{"name": "validation", "type": "json"}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Switch:22222222bbbb0003bbbb0003bbbb0003": {
|
||||
"downstream": [
|
||||
"VariableAssigner:9999999900010001000100010001cccc0001",
|
||||
"LLM:444444440002000200020002dddd0002",
|
||||
"Message:00000000eeee0003eeee0003eeee0003"
|
||||
],
|
||||
"obj": {
|
||||
"component_name": "Switch",
|
||||
"params": {
|
||||
"logical_operator": "or",
|
||||
"conditions": [
|
||||
{
|
||||
"cpn_id": "CodeExec:bbbbbbbb0001000100010001cccc0001",
|
||||
"operator": "contains",
|
||||
"value": "\"ok\": true",
|
||||
"to": "VariableAssigner:9999999900010001000100010001cccc0001"
|
||||
}
|
||||
],
|
||||
"end_cpn_ids": [
|
||||
"LLM:444444440002000200020002dddd0002",
|
||||
"Message:00000000eeee0003eeee0003eeee0003"
|
||||
],
|
||||
"operators": [
|
||||
"contains", "not contains", "=", "≠"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"VariableAssigner:9999999900010001000100010001cccc0001": {
|
||||
"downstream": ["Message:00000000eeee0004eeee0004eeee0004"],
|
||||
"obj": {
|
||||
"component_name": "VariableAssigner",
|
||||
"params": {
|
||||
"concurrent": true,
|
||||
"orders": [
|
||||
{
|
||||
"id": "research_done",
|
||||
"name": "research_done",
|
||||
"source": "literal",
|
||||
"value": "true"
|
||||
},
|
||||
{
|
||||
"id": "draft_answer",
|
||||
"name": "draft_answer",
|
||||
"source": "ref",
|
||||
"ref": "{LLM:444444440002000200020002dddd0002@draft_answer}"
|
||||
},
|
||||
{
|
||||
"id": "citations",
|
||||
"name": "citations",
|
||||
"source": "ref",
|
||||
"ref": "{LLM:444444440002000200020002dddd0002@citations}"
|
||||
}
|
||||
],
|
||||
"outputs": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"Message:00000000eeee0003eeee0003eeee0003": {
|
||||
"downstream": [],
|
||||
"obj": {
|
||||
"component_name": "Message",
|
||||
"params": {
|
||||
"content": "I couldn't validate the answer after multiple attempts. Here is my best-effort draft:\n\n{LLM:444444440002000200020002dddd0002@draft_answer}",
|
||||
"outputs": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"Message:00000000eeee0004eeee0004eeee0004": {
|
||||
"downstream": [],
|
||||
"obj": {
|
||||
"component_name": "Message",
|
||||
"params": {
|
||||
"content": "{LLM:444444440002000200020002dddd0002@draft_answer}\n\nCitations:\n{LLM:444444440002000200020002dddd0002@citations}",
|
||||
"outputs": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
85
internal/agent/dsl/testdata/v1_examples/categorize_and_agent_with_tavily.json
vendored
Normal file
85
internal/agent/dsl/testdata/v1_examples/categorize_and_agent_with_tavily.json
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"components": {
|
||||
"begin": {
|
||||
"obj":{
|
||||
"component_name": "Begin",
|
||||
"params": {
|
||||
"prologue": "Hi there!"
|
||||
}
|
||||
},
|
||||
"downstream": ["categorize:0"],
|
||||
"upstream": []
|
||||
},
|
||||
"categorize:0": {
|
||||
"obj": {
|
||||
"component_name": "Categorize",
|
||||
"params": {
|
||||
"llm_id": "deepseek-chat",
|
||||
"category_description": {
|
||||
"product_related": {
|
||||
"description": "The question is about the product usage, appearance and how it works.",
|
||||
"to": ["agent:0"]
|
||||
},
|
||||
"others": {
|
||||
"description": "The question is not about the product usage, appearance and how it works.",
|
||||
"to": ["message:0"]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"downstream": [],
|
||||
"upstream": ["begin"]
|
||||
},
|
||||
"message:0": {
|
||||
"obj":{
|
||||
"component_name": "Message",
|
||||
"params": {
|
||||
"content": [
|
||||
"Sorry, I don't know. I'm an AI bot."
|
||||
]
|
||||
}
|
||||
},
|
||||
"downstream": [],
|
||||
"upstream": ["categorize:0"]
|
||||
},
|
||||
"agent:0": {
|
||||
"obj": {
|
||||
"component_name": "Agent",
|
||||
"params": {
|
||||
"llm_id": "deepseek-chat",
|
||||
"sys_prompt": "You are a smart researcher. You could generate proper queries to search. According to the search results, you could deside next query if the result is not enough.",
|
||||
"temperature": 0.2,
|
||||
"llm_enabled_tools": [
|
||||
{
|
||||
"component_name": "TavilySearch",
|
||||
"params": {
|
||||
"api_key": "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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"downstream": ["message:1"],
|
||||
"upstream": ["categorize:0"]
|
||||
},
|
||||
"message:1": {
|
||||
"obj": {
|
||||
"component_name": "Message",
|
||||
"params": {
|
||||
"content": ["{agent:0@content}"]
|
||||
}
|
||||
},
|
||||
"downstream": [],
|
||||
"upstream": ["agent:0"]
|
||||
}
|
||||
},
|
||||
"history": [],
|
||||
"path": [],
|
||||
"retrieval": {"chunks": [], "doc_aggs": []},
|
||||
"globals": {
|
||||
"sys.query": "",
|
||||
"sys.user_id": "",
|
||||
"sys.conversation_turns": 0,
|
||||
"sys.files": []
|
||||
}
|
||||
}
|
||||
43
internal/agent/dsl/testdata/v1_examples/exesql.json
vendored
Normal file
43
internal/agent/dsl/testdata/v1_examples/exesql.json
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"components": {
|
||||
"begin": {
|
||||
"obj":{
|
||||
"component_name": "Begin",
|
||||
"params": {
|
||||
"prologue": "Hi there!"
|
||||
}
|
||||
},
|
||||
"downstream": ["answer:0"],
|
||||
"upstream": []
|
||||
},
|
||||
"answer:0": {
|
||||
"obj": {
|
||||
"component_name": "Answer",
|
||||
"params": {}
|
||||
},
|
||||
"downstream": ["exesql:0"],
|
||||
"upstream": ["begin", "exesql:0"]
|
||||
},
|
||||
"exesql:0": {
|
||||
"obj": {
|
||||
"component_name": "ExeSQL",
|
||||
"params": {
|
||||
"database": "rag_flow",
|
||||
"username": "root",
|
||||
"host": "mysql",
|
||||
"port": 3306,
|
||||
"password": "infini_rag_flow",
|
||||
"top_n": 3
|
||||
}
|
||||
},
|
||||
"downstream": ["answer:0"],
|
||||
"upstream": ["answer:0"]
|
||||
}
|
||||
},
|
||||
"history": [],
|
||||
"messages": [],
|
||||
"reference": {},
|
||||
"path": [],
|
||||
"answer": []
|
||||
}
|
||||
|
||||
210
internal/agent/dsl/testdata/v1_examples/headhunter_zh.json
vendored
Normal file
210
internal/agent/dsl/testdata/v1_examples/headhunter_zh.json
vendored
Normal file
@@ -0,0 +1,210 @@
|
||||
{
|
||||
"components": {
|
||||
"begin": {
|
||||
"obj": {
|
||||
"component_name": "Begin",
|
||||
"params": {
|
||||
"prologue": "您好!我是AGI方向的猎头,了解到您是这方面的大佬,然后冒昧的就联系到您。这边有个机会想和您分享,RAGFlow正在招聘您这个岗位的资深的工程师不知道您那边是不是感兴趣?"
|
||||
}
|
||||
},
|
||||
"downstream": ["answer:0"],
|
||||
"upstream": []
|
||||
},
|
||||
"answer:0": {
|
||||
"obj": {
|
||||
"component_name": "Answer",
|
||||
"params": {}
|
||||
},
|
||||
"downstream": ["categorize:0"],
|
||||
"upstream": ["begin", "message:reject"]
|
||||
},
|
||||
"categorize:0": {
|
||||
"obj": {
|
||||
"component_name": "Categorize",
|
||||
"params": {
|
||||
"llm_id": "deepseek-chat",
|
||||
"category_description": {
|
||||
"about_job": {
|
||||
"description": "该问题关于职位本身或公司的信息。",
|
||||
"examples": "什么岗位?\n汇报对象是谁?\n公司多少人?\n公司有啥产品?\n具体工作内容是啥?\n地点哪里?\n双休吗?",
|
||||
"to": "retrieval:0"
|
||||
},
|
||||
"casual": {
|
||||
"description": "该问题不关于职位本身或公司的信息,属于闲聊。",
|
||||
"examples": "你好\n好久不见\n你男的女的?\n你是猴子派来的救兵吗?\n上午开会了?\n你叫啥?\n最近市场如何?生意好做吗?",
|
||||
"to": "generate:casual"
|
||||
},
|
||||
"interested": {
|
||||
"description": "该回答表示他对于该职位感兴趣。",
|
||||
"examples": "嗯\n说吧\n说说看\n还好吧\n是的\n哦\nyes\n具体说说",
|
||||
"to": "message:introduction"
|
||||
},
|
||||
"answer": {
|
||||
"description": "该回答表示他对于该职位不感兴趣,或感觉受到骚扰。",
|
||||
"examples": "不需要\n不感兴趣\n暂时不看\n不要\nno\n我已经不干这个了\n我不是这个方向的",
|
||||
"to": "message:reject"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"downstream": [
|
||||
"message:introduction",
|
||||
"generate:casual",
|
||||
"message:reject",
|
||||
"retrieval:0"
|
||||
],
|
||||
"upstream": ["answer:0"]
|
||||
},
|
||||
"message:introduction": {
|
||||
"obj": {
|
||||
"component_name": "Message",
|
||||
"params": {
|
||||
"messages": [
|
||||
"我简单介绍以下:\nRAGFlow 是一款基于深度文档理解构建的开源 RAG(Retrieval-Augmented Generation)引擎。RAGFlow 可以为各种规模的企业及个人提供一套精简的 RAG 工作流程,结合大语言模型(LLM)针对用户各类不同的复杂格式数据提供可靠的问答以及有理有据的引用。https://github.com/infiniflow/ragflow\n您那边还有什么要了解的?"
|
||||
]
|
||||
}
|
||||
},
|
||||
"downstream": ["answer:1"],
|
||||
"upstream": ["categorize:0"]
|
||||
},
|
||||
"answer:1": {
|
||||
"obj": {
|
||||
"component_name": "Answer",
|
||||
"params": {}
|
||||
},
|
||||
"downstream": ["categorize:1"],
|
||||
"upstream": [
|
||||
"message:introduction",
|
||||
"generate:aboutJob",
|
||||
"generate:casual",
|
||||
"generate:get_wechat",
|
||||
"generate:nowechat"
|
||||
]
|
||||
},
|
||||
"categorize:1": {
|
||||
"obj": {
|
||||
"component_name": "Categorize",
|
||||
"params": {
|
||||
"llm_id": "deepseek-chat",
|
||||
"category_description": {
|
||||
"about_job": {
|
||||
"description": "该问题关于职位本身或公司的信息。",
|
||||
"examples": "什么岗位?\n汇报对象是谁?\n公司多少人?\n公司有啥产品?\n具体工作内容是啥?\n地点哪里?\n双休吗?",
|
||||
"to": "retrieval:0"
|
||||
},
|
||||
"casual": {
|
||||
"description": "该问题不关于职位本身或公司的信息,属于闲聊。",
|
||||
"examples": "你好\n好久不见\n你男的女的?\n你是猴子派来的救兵吗?\n上午开会了?\n你叫啥?\n最近市场如何?生意好做吗?",
|
||||
"to": "generate:casual"
|
||||
},
|
||||
"wechat": {
|
||||
"description": "该回答表示他愿意加微信,或者已经报了微信号。",
|
||||
"examples": "嗯\n可以\n是的\n哦\nyes\n15002333453\nwindblow_2231",
|
||||
"to": "generate:get_wechat"
|
||||
},
|
||||
"giveup": {
|
||||
"description": "该回答表示他不愿意加微信。",
|
||||
"examples": "不需要\n不感兴趣\n暂时不看\n不要\nno\n不方便\n不知道还要加我微信",
|
||||
"to": "generate:nowechat"
|
||||
}
|
||||
},
|
||||
"message_history_window_size": 8
|
||||
}
|
||||
},
|
||||
"downstream": [
|
||||
"retrieval:0",
|
||||
"generate:casual",
|
||||
"generate:get_wechat",
|
||||
"generate:nowechat"
|
||||
],
|
||||
"upstream": ["answer:1"]
|
||||
},
|
||||
"generate:casual": {
|
||||
"obj": {
|
||||
"component_name": "Generate",
|
||||
"params": {
|
||||
"llm_id": "deepseek-chat",
|
||||
"prompt": "你是AGI方向的猎头,现在候选人的聊了和职位无关的话题,请耐心的回应候选人,并将话题往该AGI的职位上带,最好能要到候选人微信号以便后面保持联系。",
|
||||
"temperature": 0.9,
|
||||
"message_history_window_size": 12,
|
||||
"cite": false
|
||||
}
|
||||
},
|
||||
"downstream": ["answer:1"],
|
||||
"upstream": ["categorize:0", "categorize:1"]
|
||||
},
|
||||
"retrieval:0": {
|
||||
"obj": {
|
||||
"component_name": "Retrieval",
|
||||
"params": {
|
||||
"similarity_threshold": 0.2,
|
||||
"keywords_similarity_weight": 0.3,
|
||||
"top_n": 6,
|
||||
"top_k": 1024,
|
||||
"rerank_id": "BAAI/bge-reranker-v2-m3",
|
||||
"kb_ids": ["869a236818b811ef91dffa163e197198"]
|
||||
}
|
||||
},
|
||||
"downstream": ["generate:aboutJob"],
|
||||
"upstream": ["categorize:0", "categorize:1"]
|
||||
},
|
||||
"generate:aboutJob": {
|
||||
"obj": {
|
||||
"component_name": "Generate",
|
||||
"params": {
|
||||
"llm_id": "deepseek-chat",
|
||||
"prompt": "你是AGI方向的猎头,候选人问了有关职位或公司的问题,你根据以下职位信息回答。如果职位信息中不包含候选人的问题就回答不清楚、不知道、有待确认等。回答完后引导候选人加微信号,如:\n - 方便加一下微信吗,我把JD发您看看?\n - 微信号多少,我把详细职位JD发您?\n 职位信息如下:\n {input}\n 职位信息如上。",
|
||||
"temperature": 0.02
|
||||
}
|
||||
},
|
||||
"downstream": ["answer:1"],
|
||||
"upstream": ["retrieval:0"]
|
||||
},
|
||||
"generate:get_wechat": {
|
||||
"obj": {
|
||||
"component_name": "Generate",
|
||||
"params": {
|
||||
"llm_id": "deepseek-chat",
|
||||
"prompt": "你是AGI方向的猎头,候选人表示不反感加微信,如果对方已经报了微信号,表示感谢和信任并表示马上会加上;如果没有,则问对方微信号多少。你的微信号是weixin_kevin,E-mail是kkk@ragflow.com。说话不要重复。不要总是您好。",
|
||||
"temperature": 0.1,
|
||||
"message_history_window_size": 12,
|
||||
"cite": false
|
||||
}
|
||||
},
|
||||
"downstream": ["answer:1"],
|
||||
"upstream": ["categorize:1"]
|
||||
},
|
||||
"generate:nowechat": {
|
||||
"obj": {
|
||||
"component_name": "Generate",
|
||||
"params": {
|
||||
"llm_id": "deepseek-chat",
|
||||
"prompt": "你是AGI方向的猎头,当你提出加微信时对方表示拒绝。你需要耐心礼貌的回应候选人,表示对于保护隐私信息给予理解,也可以询问他对该职位的看法和顾虑。并在恰当的时机再次询问微信联系方式。也可以鼓励候选人主动与你取得联系。你的微信号是weixin_kevin,E-mail是kkk@ragflow.com。说话不要重复。不要总是您好。",
|
||||
"temperature": 0.1,
|
||||
"message_history_window_size": 12,
|
||||
"cite": false
|
||||
}
|
||||
},
|
||||
"downstream": ["answer:1"],
|
||||
"upstream": ["categorize:1"]
|
||||
},
|
||||
"message:reject": {
|
||||
"obj": {
|
||||
"component_name": "Message",
|
||||
"params": {
|
||||
"messages": [
|
||||
"好的,祝您生活愉快,工作顺利。",
|
||||
"哦,好的,感谢您宝贵的时间!"
|
||||
]
|
||||
}
|
||||
},
|
||||
"downstream": ["answer:0"],
|
||||
"upstream": ["categorize:0"]
|
||||
}
|
||||
},
|
||||
"history": [],
|
||||
"messages": [],
|
||||
"path": [],
|
||||
"reference": [],
|
||||
"answer": []
|
||||
}
|
||||
92
internal/agent/dsl/testdata/v1_examples/iteration.json
vendored
Normal file
92
internal/agent/dsl/testdata/v1_examples/iteration.json
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
{
|
||||
"components": {
|
||||
"begin": {
|
||||
"obj":{
|
||||
"component_name": "Begin",
|
||||
"params": {
|
||||
"prologue": "Hi there!"
|
||||
}
|
||||
},
|
||||
"downstream": ["generate:0"],
|
||||
"upstream": []
|
||||
},
|
||||
"generate:0": {
|
||||
"obj": {
|
||||
"component_name": "Agent",
|
||||
"params": {
|
||||
"llm_id": "deepseek-chat",
|
||||
"sys_prompt": "You are an helpful research assistant. \nPlease decompose user's topic: '{sys.query}' into several meaningful sub-topics. \nThe output format MUST be an string array like: [\"sub-topic1\", \"sub-topic2\", ...]. Redundant information is forbidden.",
|
||||
"temperature": 0.2,
|
||||
"cite":false,
|
||||
"output_structure": ["sub-topic1", "sub-topic2", "sub-topic3"]
|
||||
}
|
||||
},
|
||||
"downstream": ["iteration:0"],
|
||||
"upstream": ["begin"]
|
||||
},
|
||||
"iteration:0": {
|
||||
"obj": {
|
||||
"component_name": "Iteration",
|
||||
"params": {
|
||||
"items_ref": "generate:0@structured_content"
|
||||
}
|
||||
},
|
||||
"downstream": ["message:0"],
|
||||
"upstream": ["generate:0"]
|
||||
},
|
||||
"iterationitem:0": {
|
||||
"obj": {
|
||||
"component_name": "IterationItem",
|
||||
"params": {}
|
||||
},
|
||||
"parent_id": "iteration:0",
|
||||
"downstream": ["tavily:0"],
|
||||
"upstream": []
|
||||
},
|
||||
"tavily:0": {
|
||||
"obj": {
|
||||
"component_name": "TavilySearch",
|
||||
"params": {
|
||||
"api_key": "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",
|
||||
"query": "iterationitem:0@result"
|
||||
}
|
||||
},
|
||||
"parent_id": "iteration:0",
|
||||
"downstream": ["generate:1"],
|
||||
"upstream": ["iterationitem:0"]
|
||||
},
|
||||
"generate:1": {
|
||||
"obj": {
|
||||
"component_name": "Agent",
|
||||
"params": {
|
||||
"llm_id": "deepseek-chat",
|
||||
"sys_prompt": "Your goal is to provide answers based on information from the internet. \nYou must use the provided search results to find relevant online information. \nYou should never use your own knowledge to answer questions.\nPlease include relevant url sources in the end of your answers.\n\n \"{tavily:0@formalized_content}\" \nUsing the above information, answer the following question or topic: \"{iterationitem:0@result} \"\nin a detailed report — The report should focus on the answer to the question, should be well structured, informative, in depth, with facts and numbers if available, a minimum of 200 words and with markdown syntax and apa format. Write all source urls at the end of the report in apa format. You should write your report only based on the given information and nothing else.",
|
||||
"temperature": 0.9,
|
||||
"cite":false
|
||||
}
|
||||
},
|
||||
"parent_id": "iteration:0",
|
||||
"downstream": ["iterationitem:0"],
|
||||
"upstream": ["tavily:0"]
|
||||
},
|
||||
"message:0": {
|
||||
"obj": {
|
||||
"component_name": "Message",
|
||||
"params": {
|
||||
"content": ["{iteration:0@generate:1}"]
|
||||
}
|
||||
},
|
||||
"downstream": [],
|
||||
"upstream": ["iteration:0"]
|
||||
}
|
||||
},
|
||||
"history": [],
|
||||
"path": [],
|
||||
"retrieval": {"chunks": [], "doc_aggs": []},
|
||||
"globals": {
|
||||
"sys.query": "",
|
||||
"sys.user_id": "",
|
||||
"sys.conversation_turns": 0,
|
||||
"sys.files": []
|
||||
}
|
||||
}
|
||||
61
internal/agent/dsl/testdata/v1_examples/retrieval_and_generate.json
vendored
Normal file
61
internal/agent/dsl/testdata/v1_examples/retrieval_and_generate.json
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"components": {
|
||||
"begin": {
|
||||
"obj":{
|
||||
"component_name": "Begin",
|
||||
"params": {
|
||||
"prologue": "Hi there!"
|
||||
}
|
||||
},
|
||||
"downstream": ["retrieval:0"],
|
||||
"upstream": []
|
||||
},
|
||||
"retrieval:0": {
|
||||
"obj": {
|
||||
"component_name": "Retrieval",
|
||||
"params": {
|
||||
"similarity_threshold": 0.2,
|
||||
"keywords_similarity_weight": 0.3,
|
||||
"top_n": 6,
|
||||
"top_k": 1024,
|
||||
"rerank_id": "",
|
||||
"empty_response": "Nothing found in dataset",
|
||||
"kb_ids": ["1a3d1d7afb0611ef9866047c16ec874f"]
|
||||
}
|
||||
},
|
||||
"downstream": ["generate:0"],
|
||||
"upstream": ["begin"]
|
||||
},
|
||||
"generate:0": {
|
||||
"obj": {
|
||||
"component_name": "LLM",
|
||||
"params": {
|
||||
"llm_id": "deepseek-chat",
|
||||
"sys_prompt": "You are an intelligent assistant. Please summarize the content of the knowledge base to answer the question. Please list the data in the knowledge base and answer in detail. When all knowledge base content is irrelevant to the question, your answer must include the sentence \"The answer you are looking for is not found in the knowledge base!\" Answers need to consider chat history.\n Here is the knowledge base:\n {retrieval:0@formalized_content}\n Above is the knowledge base.",
|
||||
"temperature": 0.2
|
||||
}
|
||||
},
|
||||
"downstream": ["message:0"],
|
||||
"upstream": ["retrieval:0"]
|
||||
},
|
||||
"message:0": {
|
||||
"obj": {
|
||||
"component_name": "Message",
|
||||
"params": {
|
||||
"content": ["{generate:0@content}"]
|
||||
}
|
||||
},
|
||||
"downstream": [],
|
||||
"upstream": ["generate:0"]
|
||||
}
|
||||
},
|
||||
"history": [],
|
||||
"path": [],
|
||||
"retrieval": {"chunks": [], "doc_aggs": []},
|
||||
"globals": {
|
||||
"sys.query": "",
|
||||
"sys.user_id": "",
|
||||
"sys.conversation_turns": 0,
|
||||
"sys.files": []
|
||||
}
|
||||
}
|
||||
95
internal/agent/dsl/testdata/v1_examples/retrieval_categorize_and_generate.json
vendored
Normal file
95
internal/agent/dsl/testdata/v1_examples/retrieval_categorize_and_generate.json
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
{
|
||||
"components": {
|
||||
"begin": {
|
||||
"obj":{
|
||||
"component_name": "Begin",
|
||||
"params": {
|
||||
"prologue": "Hi there!"
|
||||
}
|
||||
},
|
||||
"downstream": ["categorize:0"],
|
||||
"upstream": []
|
||||
},
|
||||
"categorize:0": {
|
||||
"obj": {
|
||||
"component_name": "Categorize",
|
||||
"params": {
|
||||
"llm_id": "deepseek-chat",
|
||||
"category_description": {
|
||||
"product_related": {
|
||||
"description": "The question is about the product usage, appearance and how it works.",
|
||||
"examples": [],
|
||||
"to": ["retrieval:0"]
|
||||
},
|
||||
"others": {
|
||||
"description": "The question is not about the product usage, appearance and how it works.",
|
||||
"examples": [],
|
||||
"to": ["message:0"]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"downstream": [],
|
||||
"upstream": ["begin"]
|
||||
},
|
||||
"message:0": {
|
||||
"obj":{
|
||||
"component_name": "Message",
|
||||
"params": {
|
||||
"content": [
|
||||
"Sorry, I don't know. I'm an AI bot."
|
||||
]
|
||||
}
|
||||
},
|
||||
"downstream": [],
|
||||
"upstream": ["categorize:0"]
|
||||
},
|
||||
"retrieval:0": {
|
||||
"obj": {
|
||||
"component_name": "Retrieval",
|
||||
"params": {
|
||||
"similarity_threshold": 0.2,
|
||||
"keywords_similarity_weight": 0.3,
|
||||
"top_n": 6,
|
||||
"top_k": 1024,
|
||||
"rerank_id": "",
|
||||
"empty_response": "Nothing found in dataset",
|
||||
"kb_ids": ["1a3d1d7afb0611ef9866047c16ec874f"]
|
||||
}
|
||||
},
|
||||
"downstream": ["generate:0"],
|
||||
"upstream": ["categorize:0"]
|
||||
},
|
||||
"generate:0": {
|
||||
"obj": {
|
||||
"component_name": "Agent",
|
||||
"params": {
|
||||
"llm_id": "deepseek-chat",
|
||||
"sys_prompt": "You are an intelligent assistant. Please summarize the content of the dataset to answer the question. Please list the data in the knowledge base and answer in detail. When all knowledge base content is irrelevant to the question, your answer must include the sentence \"The answer you are looking for is not found in the knowledge base!\" Answers need to consider chat history.\n Here is the knowledge base:\n {retrieval:0@formalized_content}\n The above is the knowledge base.",
|
||||
"temperature": 0.2
|
||||
}
|
||||
},
|
||||
"downstream": ["message:1"],
|
||||
"upstream": ["retrieval:0"]
|
||||
},
|
||||
"message:1": {
|
||||
"obj": {
|
||||
"component_name": "Message",
|
||||
"params": {
|
||||
"content": ["{generate:0@content}"]
|
||||
}
|
||||
},
|
||||
"downstream": [],
|
||||
"upstream": ["generate:0"]
|
||||
}
|
||||
},
|
||||
"history": [],
|
||||
"path": [],
|
||||
"retrieval": {"chunks": [], "doc_aggs": []},
|
||||
"globals": {
|
||||
"sys.query": "",
|
||||
"sys.user_id": "",
|
||||
"sys.conversation_turns": 0,
|
||||
"sys.files": []
|
||||
}
|
||||
}
|
||||
55
internal/agent/dsl/testdata/v1_examples/tavily_and_generate.json
vendored
Normal file
55
internal/agent/dsl/testdata/v1_examples/tavily_and_generate.json
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"components": {
|
||||
"begin": {
|
||||
"obj":{
|
||||
"component_name": "Begin",
|
||||
"params": {
|
||||
"prologue": "Hi there!"
|
||||
}
|
||||
},
|
||||
"downstream": ["tavily:0"],
|
||||
"upstream": []
|
||||
},
|
||||
"tavily:0": {
|
||||
"obj": {
|
||||
"component_name": "TavilySearch",
|
||||
"params": {
|
||||
"api_key": "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"
|
||||
}
|
||||
},
|
||||
"downstream": ["generate:0"],
|
||||
"upstream": ["begin"]
|
||||
},
|
||||
"generate:0": {
|
||||
"obj": {
|
||||
"component_name": "LLM",
|
||||
"params": {
|
||||
"llm_id": "deepseek-chat",
|
||||
"sys_prompt": "You are an intelligent assistant. Please summarize the content of the knowledge base to answer the question. Please list the data in the knowledge base and answer in detail. When all knowledge base content is irrelevant to the question, your answer must include the sentence \"The answer you are looking for is not found in the knowledge base!\" Answers need to consider chat history.\n Here is the knowledge base:\n {tavily:0@formalized_content}\n Above is the knowledge base.",
|
||||
"temperature": 0.2
|
||||
}
|
||||
},
|
||||
"downstream": ["message:0"],
|
||||
"upstream": ["tavily:0"]
|
||||
},
|
||||
"message:0": {
|
||||
"obj": {
|
||||
"component_name": "Message",
|
||||
"params": {
|
||||
"content": ["{generate:0@content}"]
|
||||
}
|
||||
},
|
||||
"downstream": [],
|
||||
"upstream": ["generate:0"]
|
||||
}
|
||||
},
|
||||
"history": [],
|
||||
"path": [],
|
||||
"retrieval": {"chunks": [], "doc_aggs": []},
|
||||
"globals": {
|
||||
"sys.query": "",
|
||||
"sys.user_id": "",
|
||||
"sys.conversation_turns": 0,
|
||||
"sys.files": []
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user