-
Notifications
You must be signed in to change notification settings - Fork 390
feat(examples): add HS Code Classifier trade compliance agent #569
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Subhajitdas99
wants to merge
5
commits into
GetBindu:main
Choose a base branch
from
Subhajitdas99:examples/hs-code-classifier
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+480
−0
Open
Changes from 4 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
b2a5851
feat(examples): add HS Code Classifier trade compliance agent
Subhajitdas99 0918c25
fix(examples): address CodeRabbit review comments
Subhajitdas99 5672967
fix: use pydantic Field for env var configuration in AppSettings
Subhajitdas99 5db52b7
fix: add DuckDuckGo search to back duty rates with live data
Subhajitdas99 13cf7b3
fix: add trailing newline to hs_code_classifier.py
Subhajitdas99 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| # pragma: allowlist secret | ||
| OPENROUTER_API_KEY=your_openrouter_api_key_here | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| # 🛃 HS Code Classifier | ||
|
|
||
| A Bindu trade compliance agent that classifies any product into its correct | ||
| 6-digit Harmonized System (HS) code — the international standard used by | ||
| customs authorities in every country to identify goods crossing borders. | ||
|
|
||
| Getting the HS code wrong means wrong tariffs, blocked shipments, or fines. | ||
| This agent helps SMBs get it right without hiring a trade lawyer. | ||
|
|
||
| ## Features | ||
|
|
||
| - Accepts any product description in plain English | ||
| - Returns the correct 6-digit HS code with WCO chapter heading | ||
| - Explains the classification rationale with chapter/heading/subheading references | ||
| - Provides indicative duty rates for China→EU, India→EU, China→US, India→US | ||
| - Flags common misclassification risks and required documentation | ||
| - Identifies preferential trade agreements (GSP, FTA) that may reduce duty | ||
| - Lists alternative HS codes with conditions for when each applies | ||
| - Asks clarifying questions when the product description is ambiguous | ||
|
|
||
| ## Output Format | ||
|
|
||
| ```text | ||
| HS CODE | ||
| 6109.10 — T-shirts, singlets and other vests, of cotton | ||
|
|
||
| CLASSIFICATION RATIONALE | ||
| Why this code applies, with chapter/heading/subheading references. | ||
|
|
||
| DUTY RATES | ||
| Table of indicative MFN rates for common SMB trade routes. | ||
|
|
||
| COMPLIANCE NOTES | ||
| Misclassification risks, trade agreements, required documentation. | ||
|
|
||
| ALTERNATIVE CODES | ||
| Other codes that could apply depending on product specifications. | ||
| ``` | ||
|
|
||
| ## Setup | ||
|
|
||
| ```bash | ||
| cp .env.example .env | ||
| # Add your OPENROUTER_API_KEY to .env | ||
|
|
||
| uv add bindu agno python-dotenv pydantic-settings | ||
| python hs_code_classifier.py | ||
| ``` | ||
|
|
||
| The agent runs at `http://localhost:3773`. | ||
|
|
||
| ## Example Queries | ||
|
|
||
| ```text | ||
| Classify cotton t-shirts for adults | ||
| What HS code for lithium-ion batteries used in laptops? | ||
| HS code for green coffee beans from Ethiopia | ||
| Classify unroasted arabica coffee, not decaffeinated | ||
| What code for stainless steel kitchen knives? | ||
| ``` | ||
|
|
||
| ## Project Structure | ||
|
|
||
| ```text | ||
| hs-code-classifier/ | ||
| ├── hs_code_classifier.py # Main agent + bindufy() | ||
| ├── .env.example # Environment variables | ||
| ├── skills/ | ||
| │ └── hs-classification-skill/ | ||
| │ └── skill.yaml # Skill definition | ||
| └── README.md | ||
| ``` | ||
|
|
||
| ## Environment Variables | ||
|
|
||
| | Variable | Required | Description | | ||
| |---|---|---| | ||
| | `OPENROUTER_API_KEY` | Yes | OpenRouter API key | | ||
| | `BINDU_DEPLOYMENT_URL` | No | Override default `http://localhost:3773` | | ||
|
|
||
| ## Disclaimer | ||
|
|
||
| Duty rates provided are indicative MFN rates only. Always verify against | ||
| the official tariff schedule of the importing country before filing a | ||
| customs declaration. For complex classifications, consult a licensed | ||
| customs broker or trade compliance specialist. | ||
|
|
||
| ## Why This Matters | ||
|
|
||
| Every product crossing an international border needs an HS code. Get it | ||
| wrong and you face: | ||
|
|
||
| - **Wrong tariff rates** — overpaying or underpaying duty | ||
| - **Blocked shipments** — customs holds your goods pending reclassification | ||
| - **Fines** — penalties for incorrect declarations | ||
| - **Delays** — Rotterdam container dwell averaged 9.1 days in 2025 vs a | ||
| normal 3, largely due to compliance failures | ||
|
|
||
| This agent is part of Bindu's trade compliance toolchain — a swarm of | ||
| agents helping SMBs navigate global trade without eye-watering legal bills. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,234 @@ | ||
| """ | ||
| HS Code Classifier — Bindu Example | ||
|
|
||
| A trade compliance agent that classifies products into their correct | ||
| Harmonized System (HS) codes — the 6-digit international standard used | ||
| by customs authorities in every country to identify goods crossing borders. | ||
|
|
||
| Getting the HS code wrong means wrong tariffs, blocked shipments, or fines. | ||
| This agent helps SMBs get it right without hiring a trade lawyer. | ||
|
|
||
| Features | ||
| -------- | ||
| - HS code classification backed by DuckDuckGo live web search | ||
| - Duty rates sourced from live search (not LLM memory) | ||
| - Compliance notes with misclassification risks | ||
| - Alternative codes with conditions | ||
|
|
||
| Prerequisites | ||
| ------------- | ||
| uv add bindu agno duckduckgo-search python-dotenv pydantic-settings | ||
|
|
||
| Usage | ||
| ----- | ||
| export OPENROUTER_API_KEY="your_api_key_here" # pragma: allowlist secret | ||
| python hs_code_classifier.py | ||
|
|
||
| The agent will be live at http://localhost:3773 | ||
| Example queries: | ||
| "Classify cotton t-shirts for adults" | ||
| "What HS code for lithium-ion batteries used in laptops?" | ||
| "HS code for green coffee beans from Ethiopia" | ||
| """ | ||
|
|
||
| from agno.agent import Agent | ||
| from agno.models.openrouter import OpenRouter | ||
| from agno.tools.duckduckgo import DuckDuckGoTools | ||
| from bindu.penguin.bindufy import bindufy | ||
| from bindu.utils.logging import get_logger | ||
| from dotenv import load_dotenv | ||
| from pydantic import Field | ||
| from pydantic_settings import BaseSettings | ||
|
|
||
| load_dotenv() | ||
|
|
||
| logger = get_logger(__name__) | ||
|
|
||
|
|
||
| # --------------------------------------------------------------------------- | ||
| # 1. Settings validation | ||
| # --------------------------------------------------------------------------- | ||
|
|
||
| class AppSettings(BaseSettings): | ||
| """Application settings with validation.""" | ||
|
|
||
| openrouter_api_key: str = Field(default="", alias="OPENROUTER_API_KEY") | ||
| bindu_deployment_url: str = Field( | ||
| default="http://localhost:3773", alias="BINDU_DEPLOYMENT_URL" | ||
| ) | ||
|
|
||
| class Config: | ||
| env_file = ".env" | ||
|
|
||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| def validate(self) -> None: | ||
| """Validate required settings at startup.""" | ||
| if not self.openrouter_api_key: | ||
| raise ValueError( | ||
| "OPENROUTER_API_KEY is not set. " | ||
| "Please set it in .env or as an environment variable." | ||
| ) | ||
|
|
||
|
|
||
| app_settings = AppSettings() | ||
|
|
||
|
|
||
| def validate_settings() -> None: | ||
| """Startup-time validation of required settings.""" | ||
| try: | ||
| app_settings.validate() | ||
| except ValueError as e: | ||
| logger.error("Configuration error: %s", e) | ||
| raise | ||
|
|
||
|
|
||
| # --------------------------------------------------------------------------- | ||
| # 2. Agent definition | ||
| # --------------------------------------------------------------------------- | ||
|
|
||
| INSTRUCTIONS = """ | ||
| You are an expert customs classification specialist with deep knowledge of the | ||
| Harmonized System (HS) — the international standard for classifying traded goods, | ||
| maintained by the World Customs Organization (WCO). | ||
|
|
||
| You have access to DuckDuckGo web search. You MUST use it to look up: | ||
| 1. The correct HS code for the product (search WCO or official tariff databases) | ||
| 2. Current duty rates for the trade routes requested (search official sources) | ||
| 3. Any applicable trade agreements or compliance requirements | ||
|
|
||
| Never rely on memory alone for duty rates or tariff information — always search | ||
| and cite the source. If search results are unavailable, state this explicitly | ||
| and direct the user to official sources rather than providing unverified figures. | ||
|
|
||
| When asked to classify a product, respond in this exact structure: | ||
|
|
||
| HS CODE | ||
| Provide the 6-digit HS code (format: XXXX.XX) and the official WCO chapter heading. | ||
| Cite the source used to verify this code. | ||
|
|
||
| CLASSIFICATION RATIONALE | ||
| 2-3 sentences explaining exactly why this code applies, referencing the relevant | ||
| HS chapter, heading, and subheading rules. | ||
|
|
||
| DUTY RATES | ||
| A table of indicative import duty rates for the most relevant trade routes: | ||
| - China → EU | ||
| - India → EU | ||
| - China → US | ||
| - India → US | ||
| Cite the source for each rate. Always include this disclaimer: | ||
|
|
||
| ⚠️ These rates are indicative only, sourced from web search. | ||
| Verify before filing against official schedules: | ||
| - EU TARIC: https://ec.europa.eu/taxation_customs/dds2/taric/ | ||
| - US HTS: https://hts.usitc.gov/ | ||
|
|
||
| COMPLIANCE NOTES | ||
| 2-3 bullet points covering: | ||
| - Common misclassification risks for this product type | ||
| - Any preferential trade agreements that may reduce duty (GSP, FTA) | ||
| - Required certifications or documentation for this HS code | ||
|
|
||
| ALTERNATIVE CODES | ||
| If there are common alternative codes that could apply depending on product | ||
| specifications, list them with a one-line explanation of when each applies. | ||
|
|
||
| Rules: | ||
| - Always use 6-digit HS codes (the international standard) | ||
| - If the product description is ambiguous, ask ONE clarifying question | ||
| - Never invent HS codes or duty rates — search first, then cite sources | ||
| - Output in plain Markdown | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| """.strip() | ||
|
|
||
| agent = Agent( | ||
| instructions=INSTRUCTIONS, | ||
| model=OpenRouter( | ||
| id="openai/gpt-4o-mini", | ||
| api_key=app_settings.openrouter_api_key, # pragma: allowlist secret | ||
| ), | ||
| tools=[DuckDuckGoTools()], | ||
| markdown=True, | ||
| ) | ||
|
|
||
|
|
||
| # --------------------------------------------------------------------------- | ||
| # 3. Bindu configuration | ||
| # --------------------------------------------------------------------------- | ||
|
|
||
| config = { | ||
| "author": "your.email@example.com", | ||
| "name": "hs_code_classifier", | ||
| "description": ( | ||
| "A trade compliance agent that classifies products into their correct " | ||
| "Harmonized System (HS) codes using live web search, provides sourced " | ||
| "duty rates for common trade routes, and flags compliance risks — " | ||
| "helping SMBs avoid costly customs errors." | ||
| ), | ||
| "version": "1.0.0", | ||
| "capabilities": { | ||
| "classification": ["hs-code", "customs-classification", "trade-compliance"], | ||
| "research": ["duty-rates", "trade-agreements", "compliance-notes"], | ||
| "search": ["live-tariff-lookup", "duckduckgo"], | ||
| "streaming": False, | ||
| }, | ||
| "skills": ["skills/hs-classification-skill"], | ||
| "auth": {"enabled": False}, | ||
| "storage": {"type": "memory"}, | ||
| "scheduler": {"type": "memory"}, | ||
| "deployment": { | ||
| "url": app_settings.bindu_deployment_url, | ||
| "expose": True, | ||
| "cors_origins": ["http://localhost:5173"], | ||
| }, | ||
| } | ||
|
|
||
|
|
||
| # --------------------------------------------------------------------------- | ||
| # 4. Handler | ||
| # --------------------------------------------------------------------------- | ||
|
|
||
| def handler(messages: list[dict[str, str]]): | ||
| """Classify a product into its correct HS code using live web search. | ||
|
|
||
| Args: | ||
| messages: Standard A2A message list, e.g. | ||
| [{"role": "user", "content": "Classify cotton t-shirts for adults"}] | ||
|
|
||
| Returns: | ||
| HS code, classification rationale, duty rates (sourced from web search), | ||
| compliance notes, and alternative codes. | ||
| """ | ||
| try: | ||
| user_messages = [m for m in messages if m.get("role") == "user"] | ||
| if not user_messages: | ||
| return ( | ||
| "No product description received. " | ||
| "Please describe the product you want to classify, e.g. " | ||
| "'Classify cotton t-shirts for adults'." | ||
| ) | ||
|
|
||
| query = user_messages[-1].get("content", "").strip() | ||
| if not query: | ||
| return ( | ||
| "Empty query. Please describe a product to classify, e.g. " | ||
| "'What HS code for lithium-ion batteries used in laptops?'" | ||
| ) | ||
|
|
||
| result = agent.run(input=messages) | ||
| return result | ||
|
|
||
| except Exception as e: | ||
| logger.error("Classification error: %s", e, exc_info=True) | ||
| return "Classification failed. Please try again or contact support." | ||
|
|
||
|
|
||
| # --------------------------------------------------------------------------- | ||
| # 5. Entry point | ||
| # --------------------------------------------------------------------------- | ||
|
|
||
| if __name__ == "__main__": | ||
| validate_settings() | ||
| logger.info( | ||
| "🛃 HS Code Classifier running at %s", app_settings.bindu_deployment_url | ||
| ) | ||
| logger.info("📦 Example: Classify cotton t-shirts for adults") | ||
| bindufy(config, handler) | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.