Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/loongsuite_lint_0.yml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,25 @@ jobs:
- name: Run tests
run: tox -c tox-loongsuite.ini -e lint-loongsuite-instrumentation-langchain

lint-loongsuite-instrumentation-langgraph:
name: LoongSuite loongsuite-instrumentation-langgraph
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
uses: actions/checkout@v4

- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: "3.13"

- name: Install tox
run: pip install tox-uv

- name: Run tests
run: tox -c tox-loongsuite.ini -e lint-loongsuite-instrumentation-langgraph

lint-loongsuite-instrumentation-mem0:
name: LoongSuite loongsuite-instrumentation-mem0
runs-on: ubuntu-latest
Expand Down
190 changes: 190 additions & 0 deletions .github/workflows/loongsuite_test_0.yml
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,196 @@ jobs:
- name: Run tests
run: tox -c tox-loongsuite.ini -e py313-test-loongsuite-instrumentation-langchain-latest -- -ra

py39-test-loongsuite-instrumentation-langgraph-oldest_ubuntu-latest:
name: LoongSuite loongsuite-instrumentation-langgraph-oldest 3.9 Ubuntu
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
uses: actions/checkout@v4

- name: Set up Python 3.9
uses: actions/setup-python@v5
with:
python-version: "3.9"

- name: Install tox
run: pip install tox-uv

- name: Run tests
run: tox -c tox-loongsuite.ini -e py39-test-loongsuite-instrumentation-langgraph-oldest -- -ra

py39-test-loongsuite-instrumentation-langgraph-latest_ubuntu-latest:
name: LoongSuite loongsuite-instrumentation-langgraph-latest 3.9 Ubuntu
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
uses: actions/checkout@v4

- name: Set up Python 3.9
uses: actions/setup-python@v5
with:
python-version: "3.9"

- name: Install tox
run: pip install tox-uv

- name: Run tests
run: tox -c tox-loongsuite.ini -e py39-test-loongsuite-instrumentation-langgraph-latest -- -ra

py310-test-loongsuite-instrumentation-langgraph-oldest_ubuntu-latest:
name: LoongSuite loongsuite-instrumentation-langgraph-oldest 3.10 Ubuntu
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
uses: actions/checkout@v4

- name: Set up Python 3.10
uses: actions/setup-python@v5
with:
python-version: "3.10"

- name: Install tox
run: pip install tox-uv

- name: Run tests
run: tox -c tox-loongsuite.ini -e py310-test-loongsuite-instrumentation-langgraph-oldest -- -ra

py310-test-loongsuite-instrumentation-langgraph-latest_ubuntu-latest:
name: LoongSuite loongsuite-instrumentation-langgraph-latest 3.10 Ubuntu
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
uses: actions/checkout@v4

- name: Set up Python 3.10
uses: actions/setup-python@v5
with:
python-version: "3.10"

- name: Install tox
run: pip install tox-uv

- name: Run tests
run: tox -c tox-loongsuite.ini -e py310-test-loongsuite-instrumentation-langgraph-latest -- -ra

py311-test-loongsuite-instrumentation-langgraph-oldest_ubuntu-latest:
name: LoongSuite loongsuite-instrumentation-langgraph-oldest 3.11 Ubuntu
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
uses: actions/checkout@v4

- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install tox
run: pip install tox-uv

- name: Run tests
run: tox -c tox-loongsuite.ini -e py311-test-loongsuite-instrumentation-langgraph-oldest -- -ra

py311-test-loongsuite-instrumentation-langgraph-latest_ubuntu-latest:
name: LoongSuite loongsuite-instrumentation-langgraph-latest 3.11 Ubuntu
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
uses: actions/checkout@v4

- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install tox
run: pip install tox-uv

- name: Run tests
run: tox -c tox-loongsuite.ini -e py311-test-loongsuite-instrumentation-langgraph-latest -- -ra

py312-test-loongsuite-instrumentation-langgraph-oldest_ubuntu-latest:
name: LoongSuite loongsuite-instrumentation-langgraph-oldest 3.12 Ubuntu
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
uses: actions/checkout@v4

- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install tox
run: pip install tox-uv

- name: Run tests
run: tox -c tox-loongsuite.ini -e py312-test-loongsuite-instrumentation-langgraph-oldest -- -ra

py312-test-loongsuite-instrumentation-langgraph-latest_ubuntu-latest:
name: LoongSuite loongsuite-instrumentation-langgraph-latest 3.12 Ubuntu
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
uses: actions/checkout@v4

- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install tox
run: pip install tox-uv

- name: Run tests
run: tox -c tox-loongsuite.ini -e py312-test-loongsuite-instrumentation-langgraph-latest -- -ra

py313-test-loongsuite-instrumentation-langgraph-oldest_ubuntu-latest:
name: LoongSuite loongsuite-instrumentation-langgraph-oldest 3.13 Ubuntu
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
uses: actions/checkout@v4

- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: "3.13"

- name: Install tox
run: pip install tox-uv

- name: Run tests
run: tox -c tox-loongsuite.ini -e py313-test-loongsuite-instrumentation-langgraph-oldest -- -ra

py313-test-loongsuite-instrumentation-langgraph-latest_ubuntu-latest:
name: LoongSuite loongsuite-instrumentation-langgraph-latest 3.13 Ubuntu
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
uses: actions/checkout@v4

- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: "3.13"

- name: Install tox
run: pip install tox-uv

- name: Run tests
run: tox -c tox-loongsuite.ini -e py313-test-loongsuite-instrumentation-langgraph-latest -- -ra

py310-test-loongsuite-instrumentation-mem0-oldest_ubuntu-latest:
name: LoongSuite loongsuite-instrumentation-mem0-oldest 3.10 Ubuntu
runs-on: ubuntu-latest
Expand Down
11 changes: 11 additions & 0 deletions copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ except Exception as e:

各组之间用空行分隔。

按照 PLC 0415 的规范,如非必要,导入语句原则上应该放在文件的开头。如果由于某些原因不得不放在代码中间,必须添加注释说明,并使用行内注释`# noqa: PLC0415`来避免校验失败。

### 11.2 避免重复导入

同一个模块只应导入一次,检查文件中是否存在重复的 import 语句。
Expand Down Expand Up @@ -251,3 +253,12 @@ except Exception as e:

* PR 的标题需要符合 conventional commits 规范
* PR 中需要关联工作项

---

## 22. 中英文命名约定

所有注释以及说明文档中都应遵循本约定。

* "探针"(名词)对应英文命名应使用 instrumentation,而非 probe
* "埋点"(动词)对应英文命名应使用 instrument
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

### Added

- Initial instrumentation framework for LangGraph
([#143](https://github.com/alibaba/loongsuite-python-agent/pull/143))
- Patch `create_react_agent` to set `_loongsuite_react_agent = True` flag
on `CompiledStateGraph`
- Patch `Pregel.stream` / `Pregel.astream` to inject
`metadata["_loongsuite_react_agent"]` into `RunnableConfig`, enabling
LangChain instrumentation to detect ReAct agents via callback metadata
- All patches use `wrapt.wrap_function_wrapper` /
`opentelemetry.instrumentation.utils.unwrap` (consistent with
`loongsuite-instrumentation-langchain`)
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# LongSuite LangGraph Instrumentation

OpenTelemetry instrumentation for [LangGraph](https://github.com/langchain-ai/langgraph).

## Installation

```bash
pip install loongsuite-instrumentation-langgraph
```

## Usage

```python
from opentelemetry.instrumentation.langgraph import LangGraphInstrumentor

LangGraphInstrumentor().instrument()
```

## What it does

This instrumentation patches two targets to enable LangChain instrumentation
(`loongsuite-instrumentation-langchain`) to recognise LangGraph ReAct agents
and create proper Agent / ReAct Step spans.

All patches use `wrapt.wrap_function_wrapper` (consistent with
`loongsuite-instrumentation-langchain`).

### 1. `create_react_agent` patch

Wraps `langgraph.prebuilt.create_react_agent` to set a boolean flag
`_loongsuite_react_agent = True` on the compiled `CompiledStateGraph`.
The flag itself is not accessible inside LangChain's callback system — it
only serves as the trigger for the second patch below.

### 2. `Pregel.stream` / `Pregel.astream` patch

Wraps the graph execution entry points so that when a graph carrying
`_loongsuite_react_agent = True` is invoked, the metadata
`{"_loongsuite_react_agent": True}` is injected into the `RunnableConfig`
**before** execution begins.

The data flow:

```
graph._loongsuite_react_agent = True # set by patch 1
Pregel.stream() wrapper intercepts call # patch 2
config["metadata"]["_loongsuite_react_agent"] = True
LangChain callback manager reads metadata
Run.metadata["_loongsuite_react_agent"] # LoongsuiteTracer reads this
```

LangChain's callback system automatically propagates `config["metadata"]`
to all child callbacks, so every sub-node within the graph also carries the
flag. The `LoongsuiteTracer` disambiguates the top-level graph (Agent span)
from child nodes (chain spans) by tracking an internal
`inside_langgraph_react` flag that propagates through the run hierarchy.

`Pregel.invoke()` / `ainvoke()` internally delegate to `stream` / `astream`,
so only the latter two need to be patched.

## How it works with LangChain instrumentation

When both instrumentors are active, the `LoongsuiteTracer` in the LangChain
instrumentation:

1. **Detects the agent** — `_has_langgraph_react_metadata(run)` checks
`Run.metadata` for the flag. If the parent is not already inside a
LangGraph agent, this run becomes an Agent span.

2. **Resolves agent name** — when the ReAct agent is invoked inside an
outer graph node (e.g. `product_agent`), the agent span inherits the
node's name (`invoke_agent product_agent`) instead of the generic
default (`invoke_agent LangGraph`).

3. **Tracks ReAct steps** — each time the `"agent"` node fires inside
the graph, a new ReAct Step span is created, with the hierarchy:
`Agent > ReAct Step > LLM / Tool`.

## Compatibility

- `langgraph >= 0.2`
- `langchain_core >= 0.1.0`
- Python 3.9+
Loading
Loading