ProductionAI/LLMAgentic AIAWS BedrockLangGraph
Conversational ESG Agent
How I designed a tool-calling AI agent for sustainability reporting on AWS Bedrock and LangGraph — with server-derived analytics so the model never computes a regulated figure.
~70%
Analysis Time Cut
Zero
Hallucinated Figures
RBAC
Enforced In Tools
Client work under NDA — product name, code, and live demo cannot be shared. This write-up covers my architectural approach only.
The Problem
Sustainability reporting runs on numbers that are scattered by nature. ESG (Environmental, Social, Governance) metrics live across databases, uploaded spreadsheets, and PDF filings, each with its own structure and its own terminology for the same underlying concept.
Answering a single executive question — "how did our Scope 2 emissions move quarter over quarter?" — means running several queries by hand, cross-referencing reports, and building a chart manually. It is slow, error-prone, and does not scale.
I wanted a system where an analyst could simply ask, and get an answer they could defend in a compliance review.
Why It Was Hard
A conversational layer over regulated data has far less tolerance for error than a typical chatbot.
The core challenges were: (1) Accuracy is non-negotiable — ESG figures feed compliance reporting, so an answer that is approximately right is worse than no answer, because it carries false confidence. (2) LLMs are poor at arithmetic — asking a model to compute emissions totals or period-over-period deltas invites silent numerical error. (3) Access boundaries — different roles are entitled to different slices of data, and that boundary has to hold inside a free-form chat interface where users can phrase requests any way they like. (4) Open-ended intent — users do not just ask questions, they ask for dashboards, exports, and comparisons, each needing a different capability.
Architecture
I designed the system as a tool-calling agent on AWS Bedrock, orchestrated with LangGraph.
The key architectural decisions:
→ Tools over free-form generation: the model never invents numbers. It selects and parameterises a tool — metric lookups, aggregations, comparisons, export builders — and the server executes the real query.
→ Server-derived analytics: every figure in an answer is computed server-side from source records. This is the single decision that removes numerical hallucination, because the model's role is reduced to routing and phrasing, never calculation.
→ LangGraph orchestration: multi-step requests ("compare these two sites, then chart the gap") are handled as a graph of tool calls with intermediate state, rather than one oversized prompt.
→ Authorisation at the tool boundary: access rules are enforced in the execution layer, not in the prompt. A tool call runs under the caller's role, so a user cannot talk the model into returning data they are not entitled to.
→ Generated outputs: executive dashboards and spreadsheet/PDF exports are produced from the same validated result sets that back the chat answers, so a chart and a chat reply can never disagree.
Design Tradeoffs
The instinctive approach is to retrieve context and let the model read figures out of it. For regulated reporting that is the wrong shape: fluent output makes arithmetic mistakes hard to spot, and a confident wrong total is more dangerous than an obvious failure. Moving every calculation server-side costs some flexibility but buys correctness you can actually audit.
Tool granularity was the other tradeoff worth getting right. Broad, overloaded tools are tempting because there are fewer to maintain, but they make selection ambiguous and parameters inconsistent. Narrow, single-purpose functions with strict schemas are more to build and far more reliable in practice — models choose well between precise options, and poorly within one flexible one.
Enforcing authorisation at the tool layer rather than in the prompt is a similar trade: more plumbing, but it turns an access rule from a suggestion into a guarantee.
Results
The system runs in production for enterprise sustainability teams:
• ~70% reduction in manual ESG analysis time
• Natural-language querying, dashboard generation, and data exports in one interface
• Role-based access enforced in the execution layer
• No hallucinated figures by construction — every number is server-derived
Analysts ask in plain language and get a grounded answer, a dashboard, or an export, instead of assembling each of those by hand.
Key Learnings
1. Let the LLM route, not compute. For regulated data the model should choose which trusted operation to run and phrase the result — never produce the numbers itself.
2. Many narrow tools beat few broad ones. Precise, single-purpose functions with strict schemas dramatically improve tool-selection accuracy.
3. Enforce authorisation at the tool boundary. Access rules expressed in a prompt are suggestions; access rules enforced in the execution layer are guarantees.
4. Fluency hides errors. A confident, well-written wrong answer is harder to catch than an obviously broken one, so correctness has to be structural rather than reviewed after the fact.