Spaces:
Sleeping
Sleeping
Added LangGraph version demo.
Browse files- .gitignore +1 -0
- langgraph_meta_prompt.ipynb +881 -0
- requirements.txt +38 -7
.gitignore
CHANGED
@@ -1,3 +1,4 @@
|
|
1 |
.venv
|
2 |
.vscode
|
3 |
__pycache__
|
|
|
|
1 |
.venv
|
2 |
.vscode
|
3 |
__pycache__
|
4 |
+
.env
|
langgraph_meta_prompt.ipynb
ADDED
@@ -0,0 +1,881 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"cells": [
|
3 |
+
{
|
4 |
+
"cell_type": "code",
|
5 |
+
"execution_count": 1,
|
6 |
+
"metadata": {},
|
7 |
+
"outputs": [],
|
8 |
+
"source": [
|
9 |
+
"from typing import Annotated, Sequence, Dict, Any\n",
|
10 |
+
"\n",
|
11 |
+
"from typing_extensions import TypedDict\n",
|
12 |
+
"\n",
|
13 |
+
"from langchain_openai import ChatOpenAI\n",
|
14 |
+
"\n",
|
15 |
+
"from langgraph.graph import StateGraph, END\n",
|
16 |
+
"from langgraph.graph.message import add_messages\n",
|
17 |
+
"from langchain_core.messages import HumanMessage, SystemMessage, BaseMessage\n",
|
18 |
+
"from langchain_core.prompts import ChatPromptTemplate\n",
|
19 |
+
"from langchain_core.pydantic_v1 import BaseModel\n",
|
20 |
+
"\n",
|
21 |
+
"import operator\n",
|
22 |
+
"import random\n",
|
23 |
+
"\n",
|
24 |
+
"# Can converge correctly\n",
|
25 |
+
"\n",
|
26 |
+
"MODEL_NAME = \"anthropic/claude-3.5-sonnet:beta\"\n",
|
27 |
+
"# MODEL_NAME = \"llama3-70b-8192\"\n",
|
28 |
+
"# MODEL_NAME = \"meta-llama/llama-3-70b-instruct\"\n",
|
29 |
+
"# MODEL_NAME = \"deepseek/deepseek-chat\"\n",
|
30 |
+
"# MODEL_NAME = \"qwen/qwen-2-72b-instruct\"\n",
|
31 |
+
"\n",
|
32 |
+
"# Failed to converge correctly\n",
|
33 |
+
"\n",
|
34 |
+
"# MODEL_NAME = \"llama3-8b-8192\"\n",
|
35 |
+
"# MODEL_NAME = \"mistralai/mixtral-8x22b-instruct\"\n",
|
36 |
+
"# MODEL_NAME = \"anthropic/claude-3-haiku:beta\"\n",
|
37 |
+
"# MODEL_NAME = \"google/gemma-2-9b-it\"\n",
|
38 |
+
"# MODEL_NAME = \"meta-llama/llama-3-8b-instruct\"\n",
|
39 |
+
"# MODEL_NAME = \"microsoft/phi-3-medium-128k-instruct\"\n",
|
40 |
+
"# MODEL_NAME = \"mixtral-8x7b-32768\"\n",
|
41 |
+
"# MODEL_NAME = \"cohere/command-r\"\n",
|
42 |
+
"\n",
|
43 |
+
"llm = ChatOpenAI(model_name=MODEL_NAME, temperature=0.5)\n",
|
44 |
+
"\n",
|
45 |
+
"# EXECUTOR_MODEL = \"microsoft/phi-3-medium-128k-instruct:free\"\n",
|
46 |
+
"# EXECUTOR_MODEL = \"deepseek/deepseek-chat\"\n",
|
47 |
+
"# EXECUTOR_MODEL = \"gemma-7b-it\"\n",
|
48 |
+
"# EXECUTOR_MODEL = \"llama3-8b-8192\"\n",
|
49 |
+
"# EXECUTOR_MODEL = \"llama3-70b-8192\"\n",
|
50 |
+
"# EXECUTOR_MODEL = \"mixtral-8x7b-32768\"\n",
|
51 |
+
"# EXECUTOR_MODEL = \"anthropic/claude-3-haiku:beta\"\n",
|
52 |
+
"EXECUTOR_MODEL = \"meta-llama/llama-3-8b-instruct\"\n",
|
53 |
+
"# EXECUTOR_MODEL = \"google/gemma-2-9b-it\"\n",
|
54 |
+
"\n",
|
55 |
+
"executor_llm = ChatOpenAI(model_name=EXECUTOR_MODEL, temperature=0.01)\n",
|
56 |
+
"\n",
|
57 |
+
"class AgentState(BaseModel):\n",
|
58 |
+
" # messages: Annotated[Sequence[BaseMessage], operator.add] = []\n",
|
59 |
+
" acceptance_criteria: str = \"Exactly text match.\"\n",
|
60 |
+
" user_message: str = \"\"\n",
|
61 |
+
" expected_output: str = \"\"\n",
|
62 |
+
" system_message: str = \"\"\n",
|
63 |
+
" output: str = \"\"\n",
|
64 |
+
" suggestions: str = \"\"\n",
|
65 |
+
" accepted: bool = False\n",
|
66 |
+
" analysis: str = \"\"\n",
|
67 |
+
" best_output: str = \"\"\n",
|
68 |
+
" best_system_message: str = \"\"\n",
|
69 |
+
" best_output_age: int = 0\n",
|
70 |
+
" max_output_age: int = 0\n",
|
71 |
+
"\n",
|
72 |
+
"def prompt_developer(state: AgentState) -> AgentState:\n",
|
73 |
+
" # llm = ChatOpenAI(temperature=0.1)\n",
|
74 |
+
" \n",
|
75 |
+
" if not state.system_message:\n",
|
76 |
+
" # Initial system message creation\n",
|
77 |
+
" initial_prompt = ChatPromptTemplate.from_messages([\n",
|
78 |
+
" (\"system\", \"\"\"# Expert Prompt Engineer\n",
|
79 |
+
"\n",
|
80 |
+
"You are an expert prompt engineer tasked with creating system messages for AI\n",
|
81 |
+
"assistants.\n",
|
82 |
+
"\n",
|
83 |
+
"## Instructions\n",
|
84 |
+
"\n",
|
85 |
+
"1. Create a system message based on the given user message and expected output.\n",
|
86 |
+
"2. Ensure the system message can handle similar user messages.\n",
|
87 |
+
"3. Output only the system message, without any additional content.\n",
|
88 |
+
"4. Expected Output text should not appear in System Message as an example. But\n",
|
89 |
+
" it's OK to use some similar text as an example instead.\n",
|
90 |
+
"5. Format the system message well, with no more than 80 characters per line\n",
|
91 |
+
" (except for raw text).\n",
|
92 |
+
"\n",
|
93 |
+
"## Output\n",
|
94 |
+
"\n",
|
95 |
+
"Provide only the system message, adhering to the above guidelines.\n",
|
96 |
+
"\"\"\"),\n",
|
97 |
+
" (\"human\", \"User message: {user_message}\\nExpected output: {expected_output}\\nCreate a system message that will guide the AI to produce the expected output.\")\n",
|
98 |
+
" ])\n",
|
99 |
+
" response = llm(initial_prompt.format_messages(\n",
|
100 |
+
" user_message=state.user_message, \n",
|
101 |
+
" expected_output=state.expected_output\n",
|
102 |
+
" ))\n",
|
103 |
+
" state.system_message = response.content\n",
|
104 |
+
" else:\n",
|
105 |
+
" # Update system message based on analysis\n",
|
106 |
+
" update_prompt = ChatPromptTemplate.from_messages([\n",
|
107 |
+
" (\"system\", \"\"\"# Expert Prompt Engineer\n",
|
108 |
+
"\n",
|
109 |
+
"You are an expert prompt engineer tasked with updating system messages for AI\n",
|
110 |
+
"assistants.\n",
|
111 |
+
"\n",
|
112 |
+
"## Instructions\n",
|
113 |
+
"\n",
|
114 |
+
"1. Update the system message based on the given suggestion, user message, and\n",
|
115 |
+
" expected output.\n",
|
116 |
+
"2. Ensure the updated system message can handle similar user messages.\n",
|
117 |
+
"3. Output only the updated system message, without any additional content.\n",
|
118 |
+
"4. Expected Output text should not appear in System Message as an example. But\n",
|
119 |
+
" it's OK to use some similar text as an example instead.\n",
|
120 |
+
"5. Format the system message well, with no more than 80 characters per line\n",
|
121 |
+
" (except for raw text).\n",
|
122 |
+
"\n",
|
123 |
+
"## Output\n",
|
124 |
+
"\n",
|
125 |
+
"Provide only the updated system message, adhering to the above guidelines.\n",
|
126 |
+
"\"\"\"),\n",
|
127 |
+
" (\"human\", \"\"\"Current system message: {system_message}\n",
|
128 |
+
"User message: {user_message}\n",
|
129 |
+
"Expected output: {expected_output}\n",
|
130 |
+
"Suggestions: {suggestions}\n",
|
131 |
+
" \n",
|
132 |
+
"Update the system message according to Suggestions, to improve the output and match the expected output more closely.\n",
|
133 |
+
"\"\"\")\n",
|
134 |
+
" ])\n",
|
135 |
+
" response = llm(update_prompt.format_messages(**state.dict()))\n",
|
136 |
+
" state.system_message = response.content\n",
|
137 |
+
" print(state.system_message)\n",
|
138 |
+
"\n",
|
139 |
+
" # state.messages.append(SystemMessage(content=state.system_message))\n",
|
140 |
+
" return state\n",
|
141 |
+
"\n",
|
142 |
+
"def prompt_executor(state: AgentState) -> AgentState:\n",
|
143 |
+
" # llm = ChatOpenAI(temperature=0.1)\n",
|
144 |
+
" messages = [\n",
|
145 |
+
" SystemMessage(content=state.system_message),\n",
|
146 |
+
" HumanMessage(content=state.user_message)\n",
|
147 |
+
" ]\n",
|
148 |
+
" response = executor_llm(messages)\n",
|
149 |
+
" state.output = response.content\n",
|
150 |
+
" # state.messages.append(HumanMessage(content=state.user_message))\n",
|
151 |
+
" # state.messages.append(response)\n",
|
152 |
+
"\n",
|
153 |
+
" print(response.content)\n",
|
154 |
+
"\n",
|
155 |
+
" return state\n",
|
156 |
+
"\n",
|
157 |
+
"def prompt_analyzer(state: AgentState) -> AgentState:\n",
|
158 |
+
" # Updated to compare output and expected output with LLM and format the response\n",
|
159 |
+
" comparison_prompt_template = \"\"\"\n",
|
160 |
+
"You are a text comparing program. You compare the following output texts and provide a\n",
|
161 |
+
"detailed analysis according to `Acceptance Criteria`. Then you decide whether `Actual Output`\n",
|
162 |
+
"is acceptable.\n",
|
163 |
+
"\n",
|
164 |
+
"# Expected Output\n",
|
165 |
+
"\n",
|
166 |
+
"```\n",
|
167 |
+
"{expected_output}\n",
|
168 |
+
"```\n",
|
169 |
+
"\n",
|
170 |
+
"#Actual Output\n",
|
171 |
+
"\n",
|
172 |
+
"```\n",
|
173 |
+
"{output}\n",
|
174 |
+
"```\n",
|
175 |
+
"\n",
|
176 |
+
"----\n",
|
177 |
+
"\n",
|
178 |
+
"Provide your analysis in the following format:\n",
|
179 |
+
"\n",
|
180 |
+
"```\n",
|
181 |
+
"- Acceptable Differences: [List acceptable differences succinctly]\n",
|
182 |
+
"- Unacceptable Differences: [List unacceptable differences succinctly]\n",
|
183 |
+
"- Accept: [Yes/No]\n",
|
184 |
+
"```\n",
|
185 |
+
"\n",
|
186 |
+
"* Compare Expected Output and Actual Output with the guidance of Accept Criteria.\n",
|
187 |
+
"* Only set 'Accept' to 'Yes', if Accept Criteria are all met. Otherwise, set 'Accept' to 'No'.\n",
|
188 |
+
"* List only the acceptable differences according to Accept Criteria in 'acceptable Differences' section.\n",
|
189 |
+
"* List only the unacceptable differences according to Accept Criteria in 'Unacceptable Differences' section.\n",
|
190 |
+
"\n",
|
191 |
+
"# Acceptance Criteria\n",
|
192 |
+
"\n",
|
193 |
+
"```\n",
|
194 |
+
"{acceptance_criteria}\n",
|
195 |
+
"```\n",
|
196 |
+
"\"\"\"\n",
|
197 |
+
"\n",
|
198 |
+
" comparison_prompt = ChatPromptTemplate.from_messages([\n",
|
199 |
+
" (\"system\", comparison_prompt_template)\n",
|
200 |
+
" ])\n",
|
201 |
+
" \n",
|
202 |
+
" # Format the prompt with the current state\n",
|
203 |
+
" formatted_prompt = comparison_prompt.format_messages(**state.dict())\n",
|
204 |
+
" \n",
|
205 |
+
" # Send the prompt to the LLM\n",
|
206 |
+
" response = llm(formatted_prompt)\n",
|
207 |
+
" state.analysis = response.content\n",
|
208 |
+
"\n",
|
209 |
+
" print(response.content)\n",
|
210 |
+
" \n",
|
211 |
+
" try:\n",
|
212 |
+
" # Parse the LLM response to update the state\n",
|
213 |
+
" analysis_result = parse_llm_response(response.content)\n",
|
214 |
+
" \n",
|
215 |
+
" # Update state.matched based on the LLM's analysis\n",
|
216 |
+
" state.accepted = analysis_result['Accept'].lower() == 'yes'\n",
|
217 |
+
" except KeyError:\n",
|
218 |
+
" # If the LLM response is not in the expected format, set matched to False\n",
|
219 |
+
" state.accepted = False\n",
|
220 |
+
" \n",
|
221 |
+
" return state\n",
|
222 |
+
"\n",
|
223 |
+
"def parse_llm_response(response: str) -> dict:\n",
|
224 |
+
" \"\"\"\n",
|
225 |
+
" Parses the LLM response to handle both single-line and multi-line formats for Differences and Suggestions.\n",
|
226 |
+
" \"\"\"\n",
|
227 |
+
" lines = response.split('\\n')\n",
|
228 |
+
" result = {}\n",
|
229 |
+
"\n",
|
230 |
+
" # Process each line\n",
|
231 |
+
" for line in lines:\n",
|
232 |
+
" # skip the spaces before `- `\n",
|
233 |
+
" line = line.strip()\n",
|
234 |
+
" if line.startswith('- Accept:'):\n",
|
235 |
+
" result['Accept'] = line.split(': ')[1].strip()\n",
|
236 |
+
" break\n",
|
237 |
+
"\n",
|
238 |
+
" return result\n",
|
239 |
+
"\n",
|
240 |
+
"def output_history_analyzer(state: AgentState) -> AgentState:\n",
|
241 |
+
" system_message_template = \"\"\"You are a text comparing program. You read the Acceptance Criteria, compare the\n",
|
242 |
+
"compare the exptected output with two different outputs, and decide which one is\n",
|
243 |
+
"more similar to the expected output.\n",
|
244 |
+
"\n",
|
245 |
+
"Output the ID of the output that is more similar to the expected output, with the\n",
|
246 |
+
"following format:\n",
|
247 |
+
" \n",
|
248 |
+
"```\n",
|
249 |
+
"# Better Output ID: [ID]\n",
|
250 |
+
"```\n",
|
251 |
+
"\n",
|
252 |
+
"If both outputs are equally similar to the expected output, output the following:\n",
|
253 |
+
"\n",
|
254 |
+
"```\n",
|
255 |
+
"# Draw\n",
|
256 |
+
"```\n",
|
257 |
+
"\"\"\"\n",
|
258 |
+
" human_message_templates = [\n",
|
259 |
+
" \"\"\"\n",
|
260 |
+
"# Output ID: A\n",
|
261 |
+
"\n",
|
262 |
+
"```\n",
|
263 |
+
"{best_output}\n",
|
264 |
+
"```\n",
|
265 |
+
"\n",
|
266 |
+
"# Output ID: B\n",
|
267 |
+
"\n",
|
268 |
+
"```\n",
|
269 |
+
"{output}\n",
|
270 |
+
"```\n",
|
271 |
+
"\n",
|
272 |
+
"# Acceptance Criteria\n",
|
273 |
+
"\n",
|
274 |
+
"{acceptance_criteria}\n",
|
275 |
+
"\n",
|
276 |
+
"# Expected Output\n",
|
277 |
+
"\n",
|
278 |
+
"```\n",
|
279 |
+
"{expected_output}\n",
|
280 |
+
"```\n",
|
281 |
+
"\"\"\",\n",
|
282 |
+
" \"\"\"\n",
|
283 |
+
"# Output ID: B\n",
|
284 |
+
"\n",
|
285 |
+
"```\n",
|
286 |
+
"{output}\n",
|
287 |
+
"```\n",
|
288 |
+
"\n",
|
289 |
+
"# Output ID: A\n",
|
290 |
+
"\n",
|
291 |
+
"```\n",
|
292 |
+
"{best_output}\n",
|
293 |
+
"```\n",
|
294 |
+
"\n",
|
295 |
+
"# Acceptance Criteria\n",
|
296 |
+
"\n",
|
297 |
+
"{acceptance_criteria}\n",
|
298 |
+
" \n",
|
299 |
+
"# Expected Output\n",
|
300 |
+
"\n",
|
301 |
+
"```\n",
|
302 |
+
"{expected_output}\n",
|
303 |
+
"```\n",
|
304 |
+
"\"\"\"\n",
|
305 |
+
" ]\n",
|
306 |
+
"\n",
|
307 |
+
" # pick a random human message template\n",
|
308 |
+
" output_comparison_prompt_template = ChatPromptTemplate.from_messages([\n",
|
309 |
+
" (\"system\", system_message_template),\n",
|
310 |
+
" (\"human\", human_message_templates[random.randint(0, 1)])\n",
|
311 |
+
" ])\n",
|
312 |
+
"\n",
|
313 |
+
" if (state.best_output is None or state.best_output == \"\") and \\\n",
|
314 |
+
" (state.best_system_message is None or state.best_system_message == \"\"):\n",
|
315 |
+
" state.best_output = state.output\n",
|
316 |
+
" state.best_system_message = state.system_message\n",
|
317 |
+
" state.best_output_age = 0\n",
|
318 |
+
"\n",
|
319 |
+
" return state\n",
|
320 |
+
"\n",
|
321 |
+
" response = llm(output_comparison_prompt_template.format_messages(**state.dict()))\n",
|
322 |
+
"\n",
|
323 |
+
" print(response.content)\n",
|
324 |
+
"\n",
|
325 |
+
" result = parse_output_history_analyzer(response.content, 'A')\n",
|
326 |
+
"\n",
|
327 |
+
" if result == 'A':\n",
|
328 |
+
" state.best_output_age += 1\n",
|
329 |
+
" state.output = state.best_output\n",
|
330 |
+
" state.system_message = state.best_system_message\n",
|
331 |
+
" else:\n",
|
332 |
+
" state.best_output = state.output\n",
|
333 |
+
" state.best_system_message = state.system_message\n",
|
334 |
+
" state.best_output_age = 0\n",
|
335 |
+
"\n",
|
336 |
+
" return state\n",
|
337 |
+
"\n",
|
338 |
+
"def parse_output_history_analyzer(response: str, default_result = None) -> dict:\n",
|
339 |
+
" \"\"\"\n",
|
340 |
+
" Parses the LLM response to handle both single-line and multi-line formats for Differences and Suggestions.\n",
|
341 |
+
" \"\"\"\n",
|
342 |
+
" lines = response.split('\\n')\n",
|
343 |
+
" result = default_result\n",
|
344 |
+
"\n",
|
345 |
+
" # Process each line\n",
|
346 |
+
" for line in lines:\n",
|
347 |
+
" # skip the spaces before `- `\n",
|
348 |
+
" line = line.strip()\n",
|
349 |
+
" if line.startswith('# Better Output ID:'):\n",
|
350 |
+
" result = line.split(': ')[1].strip()\n",
|
351 |
+
" break\n",
|
352 |
+
" elif line.startswith('# Draw'):\n",
|
353 |
+
" result = default_result\n",
|
354 |
+
" break\n",
|
355 |
+
"\n",
|
356 |
+
" return result\n",
|
357 |
+
"\n",
|
358 |
+
"def prompt_suggester(state: AgentState) -> AgentState:\n",
|
359 |
+
" # Updated to compare output and expected output with LLM and format the response\n",
|
360 |
+
" suggester_prompt_template = \"\"\"\n",
|
361 |
+
"Read the following inputs and outputs of an LLM prompt, and also analysis about them.\n",
|
362 |
+
"Then suggest how to improve System Prompt.\n",
|
363 |
+
"\n",
|
364 |
+
"System Prompt:\n",
|
365 |
+
"```\n",
|
366 |
+
"{system_message}\n",
|
367 |
+
"```\n",
|
368 |
+
"User Message:\n",
|
369 |
+
"```\n",
|
370 |
+
"{user_message}\n",
|
371 |
+
"```\n",
|
372 |
+
"Expected Output: \n",
|
373 |
+
"```\n",
|
374 |
+
"{expected_output}\n",
|
375 |
+
"```\n",
|
376 |
+
"Actual Output: \n",
|
377 |
+
"```\n",
|
378 |
+
"{output}\n",
|
379 |
+
"```\n",
|
380 |
+
"\n",
|
381 |
+
"Acceptance Criteria:\n",
|
382 |
+
"```\n",
|
383 |
+
"{acceptance_criteria}\n",
|
384 |
+
"```\n",
|
385 |
+
"\n",
|
386 |
+
"Analysis:\n",
|
387 |
+
"```\n",
|
388 |
+
"{analysis}\n",
|
389 |
+
"```\n",
|
390 |
+
"\n",
|
391 |
+
"* The goal is to improve the System Prompt to match the Expected Output better.\n",
|
392 |
+
"* Ignore all `Acceptable Differences` and focus on `Unacceptable Differences`.\n",
|
393 |
+
"* Provide your suggestions in a Markdown list, nothing else.\n",
|
394 |
+
"* Expected Output text should not appear in System Message as an example. But\n",
|
395 |
+
" it's OK to use some similar text as an example instead.\n",
|
396 |
+
"\"\"\"\n",
|
397 |
+
"\n",
|
398 |
+
" suggester_prompt = ChatPromptTemplate.from_messages([\n",
|
399 |
+
" (\"system\", suggester_prompt_template)\n",
|
400 |
+
" ])\n",
|
401 |
+
" \n",
|
402 |
+
" # Format the prompt with the current state\n",
|
403 |
+
" formatted_prompt = suggester_prompt.format_messages(**state.dict())\n",
|
404 |
+
" \n",
|
405 |
+
" # Send the prompt to the LLM\n",
|
406 |
+
" response = llm(formatted_prompt)\n",
|
407 |
+
" state.suggestions = response.content\n",
|
408 |
+
"\n",
|
409 |
+
" print(response.content)\n",
|
410 |
+
" \n",
|
411 |
+
" return state\n",
|
412 |
+
"\n",
|
413 |
+
"def should_exit_on_max_age(state: AgentState) -> str:\n",
|
414 |
+
" if state.max_output_age <=0:\n",
|
415 |
+
" # always continue if max age is 0\n",
|
416 |
+
" return \"continue\"\n",
|
417 |
+
" \n",
|
418 |
+
" if state.best_output_age >= state.max_output_age:\n",
|
419 |
+
" return END\n",
|
420 |
+
" \n",
|
421 |
+
" return \"continue\"\n",
|
422 |
+
"\n",
|
423 |
+
"def should_exit_on_acceptable_output(state: AgentState) -> str:\n",
|
424 |
+
" if state.accepted:\n",
|
425 |
+
" return END\n",
|
426 |
+
" else:\n",
|
427 |
+
" return \"continue\"\n",
|
428 |
+
"\n",
|
429 |
+
"\n",
|
430 |
+
"workflow = StateGraph(AgentState)\n",
|
431 |
+
"\n",
|
432 |
+
"workflow.add_node(\"prompt_developer\", prompt_developer)\n",
|
433 |
+
"workflow.add_node(\"prompt_executor\", prompt_executor)\n",
|
434 |
+
"workflow.add_node(\"output_history_analyzer\", output_history_analyzer)\n",
|
435 |
+
"workflow.add_node(\"prompt_analyzer\", prompt_analyzer)\n",
|
436 |
+
"workflow.add_node(\"prompt_suggester\", prompt_suggester)\n",
|
437 |
+
"\n",
|
438 |
+
"workflow.set_entry_point(\"prompt_developer\")\n",
|
439 |
+
"\n",
|
440 |
+
"workflow.add_edge(\"prompt_developer\", \"prompt_executor\")\n",
|
441 |
+
"workflow.add_edge(\"prompt_executor\", \"output_history_analyzer\")\n",
|
442 |
+
"\n",
|
443 |
+
"workflow.add_conditional_edges(\n",
|
444 |
+
" \"output_history_analyzer\",\n",
|
445 |
+
" should_exit_on_max_age,\n",
|
446 |
+
" {\n",
|
447 |
+
" \"continue\": \"prompt_analyzer\",\n",
|
448 |
+
" END: END\n",
|
449 |
+
" }\n",
|
450 |
+
")\n",
|
451 |
+
"\n",
|
452 |
+
"workflow.add_conditional_edges(\n",
|
453 |
+
" \"prompt_analyzer\",\n",
|
454 |
+
" should_exit_on_acceptable_output,\n",
|
455 |
+
" {\n",
|
456 |
+
" \"continue\": \"prompt_suggester\",\n",
|
457 |
+
" END: END\n",
|
458 |
+
" }\n",
|
459 |
+
")\n",
|
460 |
+
"\n",
|
461 |
+
"workflow.add_edge(\"prompt_suggester\", \"prompt_developer\")\n",
|
462 |
+
"\n",
|
463 |
+
"graph = workflow.compile()\n"
|
464 |
+
]
|
465 |
+
},
|
466 |
+
{
|
467 |
+
"cell_type": "code",
|
468 |
+
"execution_count": 2,
|
469 |
+
"metadata": {},
|
470 |
+
"outputs": [
|
471 |
+
{
|
472 |
+
"data": {
|
473 |
+
"image/jpeg": "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",
|
474 |
+
"text/plain": [
|
475 |
+
"<IPython.core.display.Image object>"
|
476 |
+
]
|
477 |
+
},
|
478 |
+
"metadata": {},
|
479 |
+
"output_type": "display_data"
|
480 |
+
}
|
481 |
+
],
|
482 |
+
"source": [
|
483 |
+
"from IPython.display import Image, display\n",
|
484 |
+
"\n",
|
485 |
+
"try:\n",
|
486 |
+
" display(Image(graph.get_graph().draw_mermaid_png()))\n",
|
487 |
+
"except Exception:\n",
|
488 |
+
" # This requires some extra dependencies and is optional\n",
|
489 |
+
" pass"
|
490 |
+
]
|
491 |
+
},
|
492 |
+
{
|
493 |
+
"cell_type": "code",
|
494 |
+
"execution_count": 3,
|
495 |
+
"metadata": {},
|
496 |
+
"outputs": [
|
497 |
+
{
|
498 |
+
"name": "stdout",
|
499 |
+
"output_type": "stream",
|
500 |
+
"text": [
|
501 |
+
"User Message: (2+8)*3\n",
|
502 |
+
"Expected Output: (2+8)*3\n",
|
503 |
+
"= 10*3\n",
|
504 |
+
"= 30\n",
|
505 |
+
"\n"
|
506 |
+
]
|
507 |
+
},
|
508 |
+
{
|
509 |
+
"name": "stderr",
|
510 |
+
"output_type": "stream",
|
511 |
+
"text": [
|
512 |
+
"/home/yale/work/meta-prompt/.venv/lib/python3.10/site-packages/langchain_core/_api/deprecation.py:139: LangChainDeprecationWarning: The method `BaseChatModel.__call__` was deprecated in langchain-core 0.1.7 and will be removed in 0.3.0. Use invoke instead.\n",
|
513 |
+
" warn_deprecated(\n"
|
514 |
+
]
|
515 |
+
},
|
516 |
+
{
|
517 |
+
"name": "stdout",
|
518 |
+
"output_type": "stream",
|
519 |
+
"text": [
|
520 |
+
"You are a step-by-step math calculator. When given a mathematical\n",
|
521 |
+
"expression:\n",
|
522 |
+
"\n",
|
523 |
+
"1. Display the original expression on the first line.\n",
|
524 |
+
"2. On the next line, show the first step of the calculation, preceded by '='.\n",
|
525 |
+
"3. Continue showing each step on a new line until the final result is reached.\n",
|
526 |
+
"4. Simplify expressions within parentheses before applying operations outside.\n",
|
527 |
+
"5. Show multiplication using the '*' symbol.\n",
|
528 |
+
"6. Do not explain the steps; simply show the calculations.\n",
|
529 |
+
"\n",
|
530 |
+
"Provide the solution using this clear, concise format to help users understand\n",
|
531 |
+
"the problem-solving process.\n",
|
532 |
+
"(2+8)*3\n",
|
533 |
+
"= 2 + 8\n",
|
534 |
+
"= 10\n",
|
535 |
+
"= 10 * 3\n",
|
536 |
+
"= 30\n",
|
537 |
+
"Based on the provided Expected Output, Actual Output, and Acceptance Criteria, here's the analysis:\n",
|
538 |
+
"\n",
|
539 |
+
"```\n",
|
540 |
+
"- Acceptable Differences: \n",
|
541 |
+
" * Extra line break at the end of the Actual Output\n",
|
542 |
+
"\n",
|
543 |
+
"- Unacceptable Differences: \n",
|
544 |
+
" * Actual Output shows intermediate steps (2 + 8 = 10) not present in Expected Output\n",
|
545 |
+
" * Actual Output separates 10 * 3 into a separate step, which is not in Expected Output\n",
|
546 |
+
"\n",
|
547 |
+
"- Accept: No\n",
|
548 |
+
"```\n",
|
549 |
+
"\n",
|
550 |
+
"The Actual Output differs significantly from the Expected Output in terms of content, showing additional steps in the calculation process that are not present in the Expected Output. These differences go beyond the acceptable criteria of extra spaces or line breaks. Therefore, the Actual Output is not acceptable according to the given Acceptance Criteria.\n",
|
551 |
+
"Here are suggestions to improve the System Prompt:\n",
|
552 |
+
"\n",
|
553 |
+
"- Add a specific instruction to simplify expressions within parentheses in a single step, without showing intermediate calculations.\n",
|
554 |
+
"- Include a clear directive to perform multiplication immediately after simplifying parentheses, without separating it into an additional step.\n",
|
555 |
+
"- Provide an example calculation in the prompt that demonstrates the desired output format, such as `(3+2)*4 = 5*4 = 20`.\n",
|
556 |
+
"- Explicitly state that only two lines of calculation should be shown for expressions with a single set of parentheses: one for simplifying the parentheses and one for the final result.\n",
|
557 |
+
"- Remove or modify the instruction about showing each step, as it may encourage unnecessary intermediate steps.\n",
|
558 |
+
"- Add a note that the solution should be as concise as possible, showing only the essential steps.\n",
|
559 |
+
"You are a step-by-step math calculator. When given a mathematical expression:\n",
|
560 |
+
"\n",
|
561 |
+
"1. Display the original expression on the first line.\n",
|
562 |
+
"2. Simplify expressions within parentheses in a single step, without showing\n",
|
563 |
+
" intermediate calculations.\n",
|
564 |
+
"3. Perform multiplication immediately after simplifying parentheses, without\n",
|
565 |
+
" separating it into an additional step.\n",
|
566 |
+
"4. Show the final result on the last line.\n",
|
567 |
+
"5. Use the '*' symbol for multiplication.\n",
|
568 |
+
"6. For expressions with a single set of parentheses, show only two lines of\n",
|
569 |
+
" calculation: one for simplifying the parentheses and one for the final\n",
|
570 |
+
" result.\n",
|
571 |
+
"7. Provide the solution in the most concise format possible, showing only\n",
|
572 |
+
" essential steps.\n",
|
573 |
+
"\n",
|
574 |
+
"Do not explain the steps; simply show the calculations. Here's an example of\n",
|
575 |
+
"the desired output format:\n",
|
576 |
+
"\n",
|
577 |
+
"(3+2)*4\n",
|
578 |
+
"= 5*4\n",
|
579 |
+
"= 20\n",
|
580 |
+
"\n",
|
581 |
+
"This clear, concise format will help users understand the problem-solving\n",
|
582 |
+
"process efficiently.\n",
|
583 |
+
"(2+8)*3\n",
|
584 |
+
"= 10*3\n",
|
585 |
+
"= 30\n",
|
586 |
+
"After comparing the two outputs with the expected output based on the given acceptance criteria, I can conclude:\n",
|
587 |
+
"\n",
|
588 |
+
"# Better Output ID: B\n",
|
589 |
+
"\n",
|
590 |
+
"Output B is more similar to the expected output. It matches the expected output exactly, with the only difference being a missing line break at the end, which is acceptable according to the criteria. Output A, while reaching the same final result, includes additional steps that are not present in the expected output.\n",
|
591 |
+
"Here's the analysis based on the provided Expected Output, Actual Output, and Acceptance Criteria:\n",
|
592 |
+
"\n",
|
593 |
+
"```\n",
|
594 |
+
"- Acceptable Differences: \n",
|
595 |
+
" * Missing line break at the end of the Actual Output.\n",
|
596 |
+
"\n",
|
597 |
+
"- Unacceptable Differences: \n",
|
598 |
+
" [None]\n",
|
599 |
+
"\n",
|
600 |
+
"- Accept: Yes\n",
|
601 |
+
"```\n",
|
602 |
+
"\n",
|
603 |
+
"The Actual Output matches the Expected Output exactly in terms of content and formatting, with the only difference being a missing line break at the end of the Actual Output. This falls under the acceptable differences as per the Acceptance Criteria, which allows for \"Extra or missing line breaks at the beginning or end of the output.\" Therefore, the Actual Output is acceptable.\n",
|
604 |
+
"Final Result: {'acceptance_criteria': '\\n* Exactly text match.\\n* Acceptable differences:\\n * Extra or missing spaces.\\n * Extra or missing line breaks at the beginning or end of the output.\\n', 'user_message': '(2+8)*3', 'expected_output': '(2+8)*3\\n= 10*3\\n= 30\\n', 'system_message': \"You are a step-by-step math calculator. When given a mathematical expression:\\n\\n1. Display the original expression on the first line.\\n2. Simplify expressions within parentheses in a single step, without showing\\n intermediate calculations.\\n3. Perform multiplication immediately after simplifying parentheses, without\\n separating it into an additional step.\\n4. Show the final result on the last line.\\n5. Use the '*' symbol for multiplication.\\n6. For expressions with a single set of parentheses, show only two lines of\\n calculation: one for simplifying the parentheses and one for the final\\n result.\\n7. Provide the solution in the most concise format possible, showing only\\n essential steps.\\n\\nDo not explain the steps; simply show the calculations. Here's an example of\\nthe desired output format:\\n\\n(3+2)*4\\n= 5*4\\n= 20\\n\\nThis clear, concise format will help users understand the problem-solving\\nprocess efficiently.\", 'output': '(2+8)*3\\n= 10*3\\n= 30', 'suggestions': 'Here are suggestions to improve the System Prompt:\\n\\n- Add a specific instruction to simplify expressions within parentheses in a single step, without showing intermediate calculations.\\n- Include a clear directive to perform multiplication immediately after simplifying parentheses, without separating it into an additional step.\\n- Provide an example calculation in the prompt that demonstrates the desired output format, such as `(3+2)*4 = 5*4 = 20`.\\n- Explicitly state that only two lines of calculation should be shown for expressions with a single set of parentheses: one for simplifying the parentheses and one for the final result.\\n- Remove or modify the instruction about showing each step, as it may encourage unnecessary intermediate steps.\\n- Add a note that the solution should be as concise as possible, showing only the essential steps.', 'accepted': True, 'analysis': 'Here\\'s the analysis based on the provided Expected Output, Actual Output, and Acceptance Criteria:\\n\\n```\\n- Acceptable Differences: \\n * Missing line break at the end of the Actual Output.\\n\\n- Unacceptable Differences: \\n [None]\\n\\n- Accept: Yes\\n```\\n\\nThe Actual Output matches the Expected Output exactly in terms of content and formatting, with the only difference being a missing line break at the end of the Actual Output. This falls under the acceptable differences as per the Acceptance Criteria, which allows for \"Extra or missing line breaks at the beginning or end of the output.\" Therefore, the Actual Output is acceptable.', 'best_output': '(2+8)*3\\n= 10*3\\n= 30', 'best_system_message': \"You are a step-by-step math calculator. When given a mathematical expression:\\n\\n1. Display the original expression on the first line.\\n2. Simplify expressions within parentheses in a single step, without showing\\n intermediate calculations.\\n3. Perform multiplication immediately after simplifying parentheses, without\\n separating it into an additional step.\\n4. Show the final result on the last line.\\n5. Use the '*' symbol for multiplication.\\n6. For expressions with a single set of parentheses, show only two lines of\\n calculation: one for simplifying the parentheses and one for the final\\n result.\\n7. Provide the solution in the most concise format possible, showing only\\n essential steps.\\n\\nDo not explain the steps; simply show the calculations. Here's an example of\\nthe desired output format:\\n\\n(3+2)*4\\n= 5*4\\n= 20\\n\\nThis clear, concise format will help users understand the problem-solving\\nprocess efficiently.\", 'best_output_age': 0, 'max_output_age': 3}\n",
|
605 |
+
"System Message:\n",
|
606 |
+
"You are a step-by-step math calculator. When given a mathematical expression:\n",
|
607 |
+
"\n",
|
608 |
+
"1. Display the original expression on the first line.\n",
|
609 |
+
"2. Simplify expressions within parentheses in a single step, without showing\n",
|
610 |
+
" intermediate calculations.\n",
|
611 |
+
"3. Perform multiplication immediately after simplifying parentheses, without\n",
|
612 |
+
" separating it into an additional step.\n",
|
613 |
+
"4. Show the final result on the last line.\n",
|
614 |
+
"5. Use the '*' symbol for multiplication.\n",
|
615 |
+
"6. For expressions with a single set of parentheses, show only two lines of\n",
|
616 |
+
" calculation: one for simplifying the parentheses and one for the final\n",
|
617 |
+
" result.\n",
|
618 |
+
"7. Provide the solution in the most concise format possible, showing only\n",
|
619 |
+
" essential steps.\n",
|
620 |
+
"\n",
|
621 |
+
"Do not explain the steps; simply show the calculations. Here's an example of\n",
|
622 |
+
"the desired output format:\n",
|
623 |
+
"\n",
|
624 |
+
"(3+2)*4\n",
|
625 |
+
"= 5*4\n",
|
626 |
+
"= 20\n",
|
627 |
+
"\n",
|
628 |
+
"This clear, concise format will help users understand the problem-solving\n",
|
629 |
+
"process efficiently.\n",
|
630 |
+
"Output:\n",
|
631 |
+
"(2+8)*3\n",
|
632 |
+
"= 10*3\n",
|
633 |
+
"= 30\n"
|
634 |
+
]
|
635 |
+
}
|
636 |
+
],
|
637 |
+
"source": [
|
638 |
+
"initial_states = [\n",
|
639 |
+
" AgentState(\n",
|
640 |
+
" max_output_age=3,\n",
|
641 |
+
" user_message=\"(2+8)*3\",\n",
|
642 |
+
" expected_output=\"\"\"(2+8)*3\n",
|
643 |
+
"= 10*3\n",
|
644 |
+
"= 30\n",
|
645 |
+
"\"\"\",\n",
|
646 |
+
" acceptance_criteria=\"\"\"\n",
|
647 |
+
"* Exactly text match.\n",
|
648 |
+
"* Acceptable differences:\n",
|
649 |
+
" * Extra or missing spaces.\n",
|
650 |
+
" * Extra or missing line breaks at the beginning or end of the output.\n",
|
651 |
+
"\"\"\"),\n",
|
652 |
+
" AgentState(\n",
|
653 |
+
" max_output_age=4,\n",
|
654 |
+
" user_message=\"\"\"Here is the GDP data in billions of US dollars (USD) for these years:\n",
|
655 |
+
"\n",
|
656 |
+
"Germany:\n",
|
657 |
+
"\n",
|
658 |
+
"2015: $3,368.29 billion\n",
|
659 |
+
"2016: $3,467.79 billion\n",
|
660 |
+
"2017: $3,677.83 billion\n",
|
661 |
+
"2018: $3,946.00 billion\n",
|
662 |
+
"2019: $3,845.03 billion\n",
|
663 |
+
"France:\n",
|
664 |
+
"\n",
|
665 |
+
"2015: $2,423.47 billion\n",
|
666 |
+
"2016: $2,465.12 billion\n",
|
667 |
+
"2017: $2,582.49 billion\n",
|
668 |
+
"2018: $2,787.86 billion\n",
|
669 |
+
"2019: $2,715.52 billion\n",
|
670 |
+
"United Kingdom:\n",
|
671 |
+
"\n",
|
672 |
+
"2015: $2,860.58 billion\n",
|
673 |
+
"2016: $2,650.90 billion\n",
|
674 |
+
"2017: $2,622.43 billion\n",
|
675 |
+
"2018: $2,828.87 billion\n",
|
676 |
+
"2019: $2,829.21 billion\n",
|
677 |
+
"Italy:\n",
|
678 |
+
"\n",
|
679 |
+
"2015: $1,815.72 billion\n",
|
680 |
+
"2016: $1,852.50 billion\n",
|
681 |
+
"2017: $1,937.80 billion\n",
|
682 |
+
"2018: $2,073.90 billion\n",
|
683 |
+
"2019: $1,988.14 billion\n",
|
684 |
+
"Spain:\n",
|
685 |
+
"\n",
|
686 |
+
"2015: $1,199.74 billion\n",
|
687 |
+
"2016: $1,235.95 billion\n",
|
688 |
+
"2017: $1,313.13 billion\n",
|
689 |
+
"2018: $1,426.19 billion\n",
|
690 |
+
"2019: $1,430.38 billion\n",
|
691 |
+
"\"\"\",\n",
|
692 |
+
" expected_output=\"\"\"Year,Germany,France,United Kingdom,Italy,Spain\n",
|
693 |
+
"2016-2015,2.96%,1.71%,-7.35%,2.02%,3.04%\n",
|
694 |
+
"2017-2016,5.08%,4.78%,-1.07%,4.61%,6.23%\n",
|
695 |
+
"2018-2017,7.48%,7.99%,7.89%,7.10%,8.58%\n",
|
696 |
+
"2019-2018,-2.56%,-2.59%,0.01%,-4.11%,0.30%\n",
|
697 |
+
"\"\"\",\n",
|
698 |
+
" acceptance_criteria=\"\"\"\n",
|
699 |
+
"* Strict text matching of the first row and first column.\n",
|
700 |
+
"* Acceptable differences:\n",
|
701 |
+
" * Differences in digital/percentage values in the table, even significant ones.\n",
|
702 |
+
" * Extra or missing spaces.\n",
|
703 |
+
" * Extra or missing line breaks.\n",
|
704 |
+
"\"\"\"),\n",
|
705 |
+
" AgentState(\n",
|
706 |
+
" max_output_age=3,\n",
|
707 |
+
" user_message=\"\"\"\n",
|
708 |
+
"基因序列:ATGGCCATGGCGCCCAGAACTGAGATCAATAGTACCCGTATTAACGGGTGA\n",
|
709 |
+
"物种:大肠杆菌 (Escherichia coli)\n",
|
710 |
+
"\"\"\",\n",
|
711 |
+
" expected_output=\"\"\"\n",
|
712 |
+
"{\n",
|
713 |
+
" \"基因序列分析结果\": {\n",
|
714 |
+
" \"基本信息\": {\n",
|
715 |
+
" \"序列长度\": 54,\n",
|
716 |
+
" \"GC含量\": \"51.85%\"\n",
|
717 |
+
" },\n",
|
718 |
+
" \"核苷酸组成\": {\n",
|
719 |
+
" \"A\": {\"数量\": 12, \"百分比\": \"22.22%\"},\n",
|
720 |
+
" \"T\": {\"数量\": 11, \"百分比\": \"20.37%\"},\n",
|
721 |
+
" \"G\": {\"数量\": 16, \"百分比\": \"29.63%\"},\n",
|
722 |
+
" \"C\": {\"数量\": 15, \"百分比\": \"27.78%\"}\n",
|
723 |
+
" },\n",
|
724 |
+
" \"密码子分析\": {\n",
|
725 |
+
" \"起始密码子\": \"ATG\",\n",
|
726 |
+
" \"终止密码子\": \"TGA\",\n",
|
727 |
+
" \"密码子表\": [\n",
|
728 |
+
" {\"密码子\": \"ATG\", \"氨基酸\": \"甲硫氨酸\", \"位置\": 1},\n",
|
729 |
+
" {\"密码子\": \"GCC\", \"氨基酸\": \"丙氨酸\", \"位置\": 2},\n",
|
730 |
+
" {\"密码子\": \"ATG\", \"氨基酸\": \"甲硫氨酸\", \"位置\": 3},\n",
|
731 |
+
" // ... 其他密码子 ...\n",
|
732 |
+
" {\"密码子\": \"TGA\", \"氨基酸\": \"终止密码子\", \"位置\": 18}\n",
|
733 |
+
" ]\n",
|
734 |
+
" },\n",
|
735 |
+
" \"潜在功能预测\": {\n",
|
736 |
+
" \"蛋白质长度\": 17,\n",
|
737 |
+
" \"可能的功能域\": [\n",
|
738 |
+
" {\"域名\": \"ABC转运蛋白\", \"起始位置\": 5, \"结束位置\": 15, \"置信度\": \"75%\"},\n",
|
739 |
+
" {\"域名\": \"膜蛋白\", \"起始位置\": 1, \"结束位置\": 17, \"置信度\": \"60%\"}\n",
|
740 |
+
" ],\n",
|
741 |
+
" \"二级结构预测\": {\n",
|
742 |
+
" \"α螺旋\": [\"2-8\", \"12-16\"],\n",
|
743 |
+
" \"β折叠\": [\"9-11\"],\n",
|
744 |
+
" \"无规卷曲\": [\"1\", \"17\"]\n",
|
745 |
+
" }\n",
|
746 |
+
" },\n",
|
747 |
+
" \"同源性分析\": {\n",
|
748 |
+
" \"最相似序列\": [\n",
|
749 |
+
" {\n",
|
750 |
+
" \"基因名\": \"abcT\",\n",
|
751 |
+
" \"物种\": \"沙门氏菌 (Salmonella enterica)\",\n",
|
752 |
+
" \"相似度\": \"89%\",\n",
|
753 |
+
" \"E值\": \"3e-25\"\n",
|
754 |
+
" },\n",
|
755 |
+
" {\n",
|
756 |
+
" \"基因名\": \"yojI\",\n",
|
757 |
+
" \"物种\": \"大肠杆菌 (Escherichia coli)\",\n",
|
758 |
+
" \"相似度\": \"95%\",\n",
|
759 |
+
" \"E值\": \"1e-30\"\n",
|
760 |
+
" }\n",
|
761 |
+
" ]\n",
|
762 |
+
" },\n",
|
763 |
+
" \"突变分析\": {\n",
|
764 |
+
" \"SNP位点\": [\n",
|
765 |
+
" {\"位置\": 27, \"野生型\": \"A\", \"突变型\": \"G\", \"氨基酸变化\": \"谷氨酰胺->精氨酸\"},\n",
|
766 |
+
" {\"位置\": 42, \"野生型\": \"C\", \"突变型\": \"T\", \"氨基酸变化\": \"无(同义突变)\"}\n",
|
767 |
+
" ]\n",
|
768 |
+
" }\n",
|
769 |
+
" }\n",
|
770 |
+
"}\n",
|
771 |
+
"\"\"\",\n",
|
772 |
+
" acceptance_criteria=\"\"\"\n",
|
773 |
+
"* Exactly text match.\n",
|
774 |
+
"* Acceptable differences:\n",
|
775 |
+
" * Extra or missing spaces\n",
|
776 |
+
" * Extra or missing line breaks at the beginning or end of the output\n",
|
777 |
+
" * Different sequence length\n",
|
778 |
+
" * Different GC content\n",
|
779 |
+
" * Different nucleotide composition\n",
|
780 |
+
" * Different codon table\n",
|
781 |
+
" * Different potential function prediction\n",
|
782 |
+
" * Different secondary structure prediction\n",
|
783 |
+
" * Different similarity analysis\n",
|
784 |
+
" * Different mutation analysis\n",
|
785 |
+
"\"\"\"),\n",
|
786 |
+
" AgentState(\n",
|
787 |
+
" max_output_age=3,\n",
|
788 |
+
" user_message=\"\"\"\n",
|
789 |
+
"今天下午3点,在北京国家会议中心,阿里巴巴集团董事局主席马云宣布将投资100亿元人民币用于农村电商发展。这一决定受到了与会代表的热烈欢迎,大家认为这将为中国农村经济带来新的机遇。\n",
|
790 |
+
"\"\"\",\n",
|
791 |
+
" expected_output=\"\"\"\n",
|
792 |
+
"{\n",
|
793 |
+
" \"文本分析结果\": {\n",
|
794 |
+
" \"情感分析\": {\n",
|
795 |
+
" \"整体情感\": \"积极\",\n",
|
796 |
+
" \"情感得分\": 0.82,\n",
|
797 |
+
" \"情感细分\": {\n",
|
798 |
+
" \"乐观\": 0.75,\n",
|
799 |
+
" \"兴奋\": 0.60,\n",
|
800 |
+
" \"期待\": 0.85\n",
|
801 |
+
" }\n",
|
802 |
+
" },\n",
|
803 |
+
" \"实体识别\": [\n",
|
804 |
+
" {\"实体\": \"北京\", \"类型\": \"地点\", \"起始位置\": 7, \"结束位置\": 9},\n",
|
805 |
+
" {\"实体\": \"国家会议中心\", \"类型\": \"地点\", \"起始位置\": 9, \"结束位置\": 15},\n",
|
806 |
+
" {\"实体\": \"阿里巴巴集团\", \"类型\": \"组织\", \"起始位置\": 16, \"结束位置\": 22},\n",
|
807 |
+
" {\"实体\": \"马云\", \"类型\": \"人物\", \"起始位置\": 26, \"结束位置\": 28},\n",
|
808 |
+
" {\"实体\": \"100亿元\", \"类型\": \"金额\", \"起始位置\": 32, \"结束位置\": 37},\n",
|
809 |
+
" {\"实体\": \"人民币\", \"类型\": \"货币\", \"起始位置\": 37, \"结束位置\": 40},\n",
|
810 |
+
" {\"实体\": \"中国\", \"类型\": \"地点\", \"起始位置\": 71, \"结束位置\": 73}\n",
|
811 |
+
" ],\n",
|
812 |
+
" \"关键词提取\": [\n",
|
813 |
+
" {\"关键词\": \"农村电商\", \"权重\": 0.95},\n",
|
814 |
+
" {\"关键词\": \"马云\", \"权重\": 0.85},\n",
|
815 |
+
" {\"关键词\": \"投资\", \"权重\": 0.80},\n",
|
816 |
+
" {\"关键词\": \"阿里巴巴\", \"权重\": 0.75},\n",
|
817 |
+
" {\"关键词\": \"经济机遇\", \"权重\": 0.70}\n",
|
818 |
+
" ]\n",
|
819 |
+
" }\n",
|
820 |
+
"}\n",
|
821 |
+
"\"\"\",\n",
|
822 |
+
" acceptance_criteria=\"\"\"\n",
|
823 |
+
"* Exactly text match, except for the numerical values.\n",
|
824 |
+
"* Acceptable differences:\n",
|
825 |
+
" * Differences in digital values in the table.\n",
|
826 |
+
" * Extra or missing spaces.\n",
|
827 |
+
" * Extra or missing line breaks at the beginning or end of the output.\n",
|
828 |
+
" * Extra or missing 3rd or 4th layer sections or items.\n",
|
829 |
+
" * Differences in section/item orders.\n",
|
830 |
+
"\"\"\")\n",
|
831 |
+
"]\n",
|
832 |
+
"\n",
|
833 |
+
"selected_states = [initial_states[0]]\n",
|
834 |
+
"\n",
|
835 |
+
"for initial_state in selected_states:\n",
|
836 |
+
" print(\"User Message:\", initial_state.user_message)\n",
|
837 |
+
" print(\"Expected Output:\", initial_state.expected_output)\n",
|
838 |
+
"\n",
|
839 |
+
" try: \n",
|
840 |
+
" result = graph.invoke(initial_state, {\"recursion_limit\": 100})\n",
|
841 |
+
" print(\"Final Result:\", result)\n",
|
842 |
+
"\n",
|
843 |
+
" # format system message, break it into multiple lines\n",
|
844 |
+
" print(\"System Message:\")\n",
|
845 |
+
" print(result['best_system_message'])\n",
|
846 |
+
" print(\"Output:\")\n",
|
847 |
+
" print(result['best_output'])\n",
|
848 |
+
" except Exception as e:\n",
|
849 |
+
" # print the error message, saying failed to converge\n",
|
850 |
+
" print(\"Failed to converge.\")\n",
|
851 |
+
" print(e)\n",
|
852 |
+
"\n",
|
853 |
+
" print(\"System Message:\")\n",
|
854 |
+
" print(result['best_system_message'])\n",
|
855 |
+
" print(\"Output:\")\n",
|
856 |
+
" print(result['best_output'])"
|
857 |
+
]
|
858 |
+
}
|
859 |
+
],
|
860 |
+
"metadata": {
|
861 |
+
"kernelspec": {
|
862 |
+
"display_name": ".venv",
|
863 |
+
"language": "python",
|
864 |
+
"name": "python3"
|
865 |
+
},
|
866 |
+
"language_info": {
|
867 |
+
"codemirror_mode": {
|
868 |
+
"name": "ipython",
|
869 |
+
"version": 3
|
870 |
+
},
|
871 |
+
"file_extension": ".py",
|
872 |
+
"mimetype": "text/x-python",
|
873 |
+
"name": "python",
|
874 |
+
"nbconvert_exporter": "python",
|
875 |
+
"pygments_lexer": "ipython3",
|
876 |
+
"version": "3.10.12"
|
877 |
+
}
|
878 |
+
},
|
879 |
+
"nbformat": 4,
|
880 |
+
"nbformat_minor": 2
|
881 |
+
}
|
requirements.txt
CHANGED
@@ -4,15 +4,21 @@ aiosignal==1.3.1
|
|
4 |
altair==5.1.1
|
5 |
annotated-types==0.5.0
|
6 |
anyio==3.7.1
|
|
|
7 |
async-timeout==4.0.3
|
8 |
attrs==23.1.0
|
9 |
certifi==2023.7.22
|
10 |
charset-normalizer==3.2.0
|
11 |
click==8.1.7
|
|
|
12 |
contourpy==1.1.1
|
13 |
cycler==0.11.0
|
14 |
dataclasses-json==0.6.0
|
15 |
-
|
|
|
|
|
|
|
|
|
16 |
fastapi==0.103.1
|
17 |
ffmpy==0.3.1
|
18 |
filelock==3.12.4
|
@@ -28,36 +34,56 @@ httpx==0.25.0
|
|
28 |
huggingface-hub==0.17.2
|
29 |
idna==3.4
|
30 |
importlib-resources==6.1.0
|
|
|
|
|
|
|
31 |
Jinja2==3.1.2
|
32 |
joblib==1.3.2
|
33 |
jsonpatch==1.33
|
34 |
jsonpointer==2.4
|
35 |
jsonschema==4.19.1
|
36 |
jsonschema-specifications==2023.7.1
|
|
|
|
|
37 |
kiwisolver==1.4.5
|
38 |
langchain==0.0.300
|
39 |
-
|
|
|
|
|
|
|
40 |
MarkupSafe==2.1.3
|
41 |
marshmallow==3.20.1
|
42 |
matplotlib==3.8.0
|
|
|
43 |
multidict==6.0.4
|
44 |
mypy-extensions==1.0.0
|
|
|
45 |
numexpr==2.8.6
|
46 |
numpy==1.26.0
|
47 |
-
openai==
|
48 |
-
orjson==3.
|
49 |
-
packaging==
|
50 |
pandas==2.1.1
|
|
|
|
|
51 |
Pillow==10.0.1
|
|
|
|
|
|
|
|
|
|
|
52 |
pydantic==2.3.0
|
53 |
pydantic_core==2.6.3
|
54 |
pydub==0.25.1
|
|
|
55 |
pyparsing==3.1.1
|
56 |
-
python-dateutil==2.
|
57 |
python-multipart==0.0.6
|
58 |
pytz==2023.3.post1
|
59 |
PyYAML==6.0.1
|
|
|
60 |
referencing==0.30.2
|
|
|
61 |
requests==2.31.0
|
62 |
rpds-py==0.10.3
|
63 |
scikit-learn==1.3.1
|
@@ -66,15 +92,20 @@ semantic-version==2.10.0
|
|
66 |
six==1.16.0
|
67 |
sniffio==1.3.0
|
68 |
SQLAlchemy==2.0.21
|
|
|
69 |
starlette==0.27.0
|
70 |
tenacity==8.2.3
|
71 |
threadpoolctl==3.2.0
|
|
|
72 |
toolz==0.12.0
|
|
|
73 |
tqdm==4.66.1
|
|
|
74 |
typing-inspect==0.9.0
|
75 |
-
typing_extensions==4.
|
76 |
tzdata==2023.3
|
77 |
urllib3==2.0.5
|
78 |
uvicorn==0.23.2
|
|
|
79 |
websockets==11.0.3
|
80 |
yarl==1.9.2
|
|
|
4 |
altair==5.1.1
|
5 |
annotated-types==0.5.0
|
6 |
anyio==3.7.1
|
7 |
+
asttokens==2.4.1
|
8 |
async-timeout==4.0.3
|
9 |
attrs==23.1.0
|
10 |
certifi==2023.7.22
|
11 |
charset-normalizer==3.2.0
|
12 |
click==8.1.7
|
13 |
+
comm==0.2.2
|
14 |
contourpy==1.1.1
|
15 |
cycler==0.11.0
|
16 |
dataclasses-json==0.6.0
|
17 |
+
debugpy==1.8.2
|
18 |
+
decorator==5.1.1
|
19 |
+
distro==1.9.0
|
20 |
+
exceptiongroup==1.2.1
|
21 |
+
executing==2.0.1
|
22 |
fastapi==0.103.1
|
23 |
ffmpy==0.3.1
|
24 |
filelock==3.12.4
|
|
|
34 |
huggingface-hub==0.17.2
|
35 |
idna==3.4
|
36 |
importlib-resources==6.1.0
|
37 |
+
ipykernel==6.29.4
|
38 |
+
ipython==8.26.0
|
39 |
+
jedi==0.19.1
|
40 |
Jinja2==3.1.2
|
41 |
joblib==1.3.2
|
42 |
jsonpatch==1.33
|
43 |
jsonpointer==2.4
|
44 |
jsonschema==4.19.1
|
45 |
jsonschema-specifications==2023.7.1
|
46 |
+
jupyter_client==8.6.2
|
47 |
+
jupyter_core==5.7.2
|
48 |
kiwisolver==1.4.5
|
49 |
langchain==0.0.300
|
50 |
+
langchain-core==0.2.10
|
51 |
+
langchain-openai==0.1.13
|
52 |
+
langgraph==0.1.4
|
53 |
+
langsmith==0.1.82
|
54 |
MarkupSafe==2.1.3
|
55 |
marshmallow==3.20.1
|
56 |
matplotlib==3.8.0
|
57 |
+
matplotlib-inline==0.1.7
|
58 |
multidict==6.0.4
|
59 |
mypy-extensions==1.0.0
|
60 |
+
nest-asyncio==1.6.0
|
61 |
numexpr==2.8.6
|
62 |
numpy==1.26.0
|
63 |
+
openai==1.35.7
|
64 |
+
orjson==3.10.5
|
65 |
+
packaging==24.1
|
66 |
pandas==2.1.1
|
67 |
+
parso==0.8.4
|
68 |
+
pexpect==4.9.0
|
69 |
Pillow==10.0.1
|
70 |
+
platformdirs==4.2.2
|
71 |
+
prompt_toolkit==3.0.47
|
72 |
+
psutil==6.0.0
|
73 |
+
ptyprocess==0.7.0
|
74 |
+
pure-eval==0.2.2
|
75 |
pydantic==2.3.0
|
76 |
pydantic_core==2.6.3
|
77 |
pydub==0.25.1
|
78 |
+
Pygments==2.18.0
|
79 |
pyparsing==3.1.1
|
80 |
+
python-dateutil==2.9.0.post0
|
81 |
python-multipart==0.0.6
|
82 |
pytz==2023.3.post1
|
83 |
PyYAML==6.0.1
|
84 |
+
pyzmq==26.0.3
|
85 |
referencing==0.30.2
|
86 |
+
regex==2024.5.15
|
87 |
requests==2.31.0
|
88 |
rpds-py==0.10.3
|
89 |
scikit-learn==1.3.1
|
|
|
92 |
six==1.16.0
|
93 |
sniffio==1.3.0
|
94 |
SQLAlchemy==2.0.21
|
95 |
+
stack-data==0.6.3
|
96 |
starlette==0.27.0
|
97 |
tenacity==8.2.3
|
98 |
threadpoolctl==3.2.0
|
99 |
+
tiktoken==0.7.0
|
100 |
toolz==0.12.0
|
101 |
+
tornado==6.4.1
|
102 |
tqdm==4.66.1
|
103 |
+
traitlets==5.14.3
|
104 |
typing-inspect==0.9.0
|
105 |
+
typing_extensions==4.12.2
|
106 |
tzdata==2023.3
|
107 |
urllib3==2.0.5
|
108 |
uvicorn==0.23.2
|
109 |
+
wcwidth==0.2.13
|
110 |
websockets==11.0.3
|
111 |
yarl==1.9.2
|