Skip to content

Commit 0fcb784

Browse files
committed
fix: refactor test_integration.py for compatibility with updated LangChain APIs
- Replaced deprecated `langchain-classic` usage with `langsmith.Client` integration. - Updated prompt handling and switched from `create_react_agent` to `create_agent`. - Refactored mock server implementation for streamlined testing. - Improved async and sync agent execution methods. - Refined LangGraph-based workflows and updated calculator tool usage. - Enhanced AutoGen and MCP agent configurations to ensure alignment with updated APIs.
1 parent 63b6d42 commit 0fcb784

File tree

7 files changed

+2138
-3786
lines changed

7 files changed

+2138
-3786
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,3 +216,5 @@ agentlightning/dashboard/**/*.svg
216216

217217
# Docker data
218218
docker/data/
219+
/.envrc
220+
/.gitattributes

agentlightning/execution/client_server.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@
44
import logging
55
import multiprocessing
66
import os
7+
import sys
8+
9+
if sys.platform == "darwin":
10+
# 允许 macOS 使用 fork (尽管 Apple 认为不安全)
11+
os.environ["OBJC_DISABLE_INITIALIZE_FORK_SAFETY"] = "YES"
12+
try:
13+
multiprocessing.set_start_method("fork", force=True)
14+
print("⚡️ [HACK] Force-enabled 'fork' start method for macOS.")
15+
except RuntimeError:
16+
pass
717
import signal
818
import time
919
from multiprocessing.context import BaseContext
@@ -196,6 +206,13 @@ async def _execute_runner(
196206
else:
197207
logger.debug("Runner %s closed LightningStore client", worker_id)
198208

209+
def _runner_sync(
210+
self, runner: RunnerBundle, worker_id: int, store: LightningStore, stop_evt: ExecutionEvent
211+
) -> None:
212+
# Runners are executed in child processes; each process owns its own
213+
# event loop to keep the asyncio scheduler isolated.
214+
asyncio.run(self._execute_runner(runner, worker_id, store, stop_evt))
215+
199216
def _spawn_runners(
200217
self,
201218
runner: RunnerBundle,
@@ -206,16 +223,10 @@ def _spawn_runners(
206223
) -> list[multiprocessing.Process]:
207224
"""Used when `role == "runner"` or `role == "both"` and `n_runners > 1`."""
208225
processes: list[multiprocessing.Process] = []
209-
210-
def _runner_sync(runner: RunnerBundle, worker_id: int, store: LightningStore, stop_evt: ExecutionEvent) -> None:
211-
# Runners are executed in child processes; each process owns its own
212-
# event loop to keep the asyncio scheduler isolated.
213-
asyncio.run(self._execute_runner(runner, worker_id, store, stop_evt))
214-
215226
for i in range(self.n_runners):
216227
process = cast(
217228
multiprocessing.Process,
218-
ctx.Process(target=_runner_sync, args=(runner, i, store, stop_evt), name=f"runner-{i}"), # type: ignore
229+
ctx.Process(target=self._runner_sync, args=(runner, i, store, stop_evt), name=f"runner-{i}"), # type: ignore
219230
)
220231
process.start()
221232
logger.debug("Spawned runner process %s (pid=%s)", process.name, process.pid)

examples/spider/sql_agent.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import time
1818
from typing import Any, Dict, List, Literal, Optional, cast
1919

20+
import numpy as np
2021
import pandas as pd
2122
import termcolor
2223
from langchain.chat_models import init_chat_model
@@ -34,14 +35,13 @@
3435

3536
logger = logging.getLogger(__name__)
3637

37-
3838
WRITE_QUERY_PROMPT = ChatPromptTemplate(
3939
[
4040
(
4141
"system",
4242
"""
4343
You are an agent designed to interact with a SQL database.
44-
Given an input question, create a syntactically correct {dialect} query to run to help find the answer.
44+
Given an input question, create a syntactically correct {dialect} query to run to help find the answer.
4545
4646
Pay attention to use only the column names that you can see in the schema description.
4747
Be careful to not query for columns that do not exist.
@@ -65,7 +65,6 @@
6565
]
6666
)
6767

68-
6968
CHECK_QUERY_PROMPT = ChatPromptTemplate(
7069
[
7170
(
@@ -117,7 +116,6 @@
117116
]
118117
)
119118

120-
121119
REWRITE_QUERY_PROMPT = ChatPromptTemplate(
122120
[
123121
(
@@ -525,7 +523,12 @@ def debug_sql_agent():
525523
spider_dev_data_path = os.path.join(os.environ.get("VERL_SPIDER_DATA_DIR", "data"), "dev.parquet")
526524
if not os.path.exists(spider_dev_data_path):
527525
raise FileNotFoundError(f"Spider dev data file {spider_dev_data_path} does not exist.")
528-
df = pd.read_parquet(spider_dev_data_path).head(10) # type: ignore
526+
df: pd.DataFrame = pd.read_parquet(spider_dev_data_path).head(10) # type: ignore
527+
528+
def numpy_to_list(x: np.ndarray) -> list:
529+
return x.tolist()
530+
531+
df: pd.DataFrame = df.applymap(numpy_to_list)
529532
df = cast(List[Dict[str, Any]], df.to_dict(orient="records")) # type: ignore
530533
print("Debug data:", df)
531534

examples/spider/train_sql_agent.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ def config_train_fast() -> Dict[str, Any]:
127127
config["trainer"]["experiment_name"] = EXPERIMENT_NAME
128128
config["trainer"]["project_name"] = PROJECT_NAME
129129
config["trainer"]["test_freq"] = 1
130+
130131
return config
131132

132133

pyproject.toml

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ dev = [
6666
"mkdocs-macros-plugin",
6767
"mkdocs-autorefs",
6868
"prometheus-client",
69+
"sqlparse>=0.5.3",
70+
"pyarrow>=22.0.0",
71+
"fastparquet>=2024.11.0",
72+
"pandas>=2.3.3",
73+
"hydra-core>=1.3.2",
74+
"tensordict>=0.10.0",
75+
"verl>=0.7.1.dev0",
6976
]
7077
experiment = [
7178
"random-word",
@@ -182,10 +189,13 @@ anthropic = [
182189
"anthropic",
183190
]
184191
langchain = [
185-
"langgraph<1.0",
186-
"langchain[openai]<1.0",
192+
"langgraph",
193+
"langchain>=1.0.0",
194+
"langchain-openai",
187195
"langchain-community",
188-
"langchain-text-splitters<1.0",
196+
"langchain-text-splitters",
197+
"langsmith>=0.3.45",
198+
"langchain-classic>=1.0.0",
189199
]
190200
sql = [
191201
"sqlparse",
@@ -227,7 +237,7 @@ conflicts = [
227237
],
228238
]
229239
environments = [
230-
"sys_platform == 'linux'",
240+
# "sys_platform == 'linux'",
231241
]
232242
dependency-metadata = [
233243
# Patch the dependencies of instructor to unpin "openai".
@@ -249,6 +259,7 @@ torch = [
249259
{ index = "pytorch-cpu", group = "torch-cpu" },
250260
]
251261
tinker_cookbook = { git = "https://github.com/thinking-machines-lab/tinker-cookbook" }
262+
verl = {git = "https://github.com/Acture/verl.git"}
252263

253264
[[tool.uv.index]]
254265
name = "pypi"
@@ -303,6 +314,7 @@ markers = [
303314
"agentops: tests that require AgentOps",
304315
"llmproxy: tests that require LiteLLM",
305316
"mongo: tests that require MongoDB",
317+
"langchain: tests that require or relate to LangChain",
306318
]
307319

308320
[tool.black]

tests/tracer/test_integration.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@
5050
from autogen_ext.models.openai import OpenAIChatCompletionClient
5151
from autogen_ext.tools.mcp import McpWorkbench, StdioServerParams
5252
from fastapi import FastAPI
53-
from langchain import hub
54-
from langchain.agents import AgentExecutor, create_react_agent, tool
53+
from langchain.agents import create_agent
5554
from langchain.chat_models import init_chat_model
55+
from langchain.tools import tool
5656
from langchain_community.agent_toolkits import SQLDatabaseToolkit
5757
from langchain_community.utilities import SQLDatabase
5858
from langchain_core.messages import AIMessage, BaseMessage, HumanMessage, ToolMessage
@@ -61,6 +61,7 @@
6161
from langchain_openai import ChatOpenAI
6262
from langgraph.graph import END, START, MessagesState, StateGraph
6363
from langgraph.prebuilt import ToolNode
64+
from langsmith import Client as LangsmithClient
6465
from openai import AsyncOpenAI, OpenAI
6566
from opentelemetry.sdk.trace import ReadableSpan
6667
from pydantic import BaseModel, Field
@@ -86,7 +87,6 @@
8687
REAL_OPENAI_BASE_URL is not None and REAL_OPENAI_API_KEY is not None
8788
), "OPENAI_BASE_URL and OPENAI_API_KEY must be set when USE_OPENAI is true"
8889

89-
9090
_langchain_callback_handler = None
9191

9292

@@ -133,7 +133,7 @@ def normalize_messages(msgs: List[Dict[str, Any]]) -> str:
133133
# Flatten messages to a string for comparison
134134
if not msgs:
135135
return ""
136-
return "\n".join(f"{m.get('role','')}:{m.get('content','')}" for m in msgs)
136+
return "\n".join(f"{m.get('role', '')}:{m.get('content', '')}" for m in msgs)
137137

138138
req_msgs = request_dict.get("messages", [])
139139
req_tools = request_dict.get("tools", "")
@@ -275,6 +275,7 @@ def agent_litellm() -> None:
275275
assert "4" in response.choices[0].message.content
276276

277277

278+
@pytest.mark.langchain
278279
def agent_langchain() -> None:
279280
"""A simple LangChain agent."""
280281
llm = ChatOpenAI(model=OPENAI_MODEL, openai_api_base=OPENAI_BASE_URL, openai_api_key=OPENAI_API_KEY)
@@ -284,6 +285,7 @@ def agent_langchain() -> None:
284285
assert "Paris" in result
285286

286287

288+
@pytest.mark.langchain
287289
def agent_langchain_tooluse() -> None:
288290
"""A LangChain agent that uses a calculator tool."""
289291

@@ -301,15 +303,18 @@ def multiply(a_and_b: str) -> int:
301303
disable_streaming=True,
302304
)
303305
tools = [multiply]
304-
agent = create_react_agent(llm, tools, hub.pull("hwchase17/react"))
305-
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=False)
306-
result = agent_executor.invoke(
307-
{"input": "what is 42 * 12"},
308-
{"callbacks": [_langchain_callback_handler]} if _langchain_callback_handler else None,
306+
hub = LangsmithClient()
307+
prompt_tmp: PromptTemplate = hub.pull_prompt("hwchase17/react")
308+
309+
prompt = prompt_tmp.format_prompt(
310+
tools=[multiply.description], tool_names=multiply.name, input="what is 42 * 12", agent_scratchpad=""
309311
)
312+
agent = create_agent(llm, tools)
313+
result = agent.invoke(input=prompt)
310314
assert "504" in result["output"]
311315

312316

317+
@pytest.mark.langchain
313318
def agent_langgraph() -> None:
314319
"""An agent built with LangGraph for stateful, cyclical workflows."""
315320
llm = init_chat_model("openai:" + OPENAI_MODEL, openai_api_base=OPENAI_BASE_URL, openai_api_key=OPENAI_API_KEY)
@@ -526,7 +531,6 @@ async def openai_agents_sdk_mcp_tool_use() -> None:
526531

527532

528533
async def openai_agents_sdk_handoff_tool_output_type_and_reward() -> None:
529-
530534
class MathOutput(BaseModel):
531535
answer: int
532536

@@ -918,4 +922,4 @@ def _debug_with_agentops():
918922
if __name__ == "__main__":
919923
# run_with_agentops_tracer()
920924
run_with_http_tracer()
921-
# _debug_with_agentops()
925+
# _debug_with_agentops()

0 commit comments

Comments
 (0)